Hibernate SVN: r18855 - in core/trunk/cache-jbosscache/src: test/java/org/hibernate/test/cache/jbc/access and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2010-02-22 21:11:31 -0500 (Mon, 22 Feb 2010)
New Revision: 18855
Modified:
core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/OptimisticTransactionalAccessDelegate.java
core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/PutFromLoadValidator.java
core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/TransactionalAccessDelegate.java
core/trunk/cache-jbosscache/src/test/java/org/hibernate/test/cache/jbc/access/PutFromLoadValidatorUnitTestCase.java
Log:
[HHH-3817] Better handle race between putFromLoad and removal
Modified: core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/OptimisticTransactionalAccessDelegate.java
===================================================================
--- core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/OptimisticTransactionalAccessDelegate.java 2010-02-23 01:12:57 UTC (rev 18854)
+++ core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/OptimisticTransactionalAccessDelegate.java 2010-02-23 02:11:31 UTC (rev 18855)
@@ -63,7 +63,9 @@
*/
@Override
public void evict(Object key) throws CacheException {
- putValidator.keyRemoved(key);
+ if (!putValidator.invalidateKey(key)) {
+ throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
+ }
region.ensureRegionRootExists();
Option opt = NonLockingDataVersion.getInvocationOption();
@@ -75,7 +77,9 @@
@Override
public void evictAll() throws CacheException
{
- putValidator.regionRemoved();
+ if (!putValidator.invalidateRegion()) {
+ throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
+ }
Transaction tx = region.suspend();
try {
@@ -116,16 +120,21 @@
if (!region.checkValid())
return false;
- if (!putValidator.isPutValid(key))
+ if (!putValidator.acquirePutFromLoadLock(key))
return false;
- region.ensureRegionRootExists();
-
- // We ignore minimalPutOverride. JBossCache putForExternalRead is
- // already about as minimal as we can get; it will promptly return
- // if it discovers that the node we want to write to already exists
- Option opt = getDataVersionOption(version, version);
- return CacheHelper.putForExternalRead(cache, regionFqn, key, value, opt);
+ try {
+ region.ensureRegionRootExists();
+
+ // We ignore minimalPutOverride. JBossCache putForExternalRead is
+ // already about as minimal as we can get; it will promptly return
+ // if it discovers that the node we want to write to already exists
+ Option opt = getDataVersionOption(version, version);
+ return CacheHelper.putForExternalRead(cache, regionFqn, key, value, opt);
+ }
+ finally {
+ putValidator.releasePutFromLoadLock(key);
+ }
}
@Override
@@ -134,19 +143,26 @@
if (!region.checkValid())
return false;
- if (!putValidator.isPutValid(key))
+ if (!putValidator.acquirePutFromLoadLock(key))
return false;
- region.ensureRegionRootExists();
-
- Option opt = getDataVersionOption(version, version);
- return CacheHelper.putForExternalRead(cache, regionFqn, key, value, opt);
+ try {
+ region.ensureRegionRootExists();
+
+ Option opt = getDataVersionOption(version, version);
+ return CacheHelper.putForExternalRead(cache, regionFqn, key, value, opt);
+ }
+ finally {
+ putValidator.releasePutFromLoadLock(key);
+ }
}
@Override
public void remove(Object key) throws CacheException {
- putValidator.keyRemoved(key);
+ if (!putValidator.invalidateKey(key)) {
+ throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
+ }
// We remove whether or not the region is valid. Other nodes
// may have already restored the region so they need to
@@ -160,7 +176,9 @@
@Override
public void removeAll() throws CacheException {
- putValidator.regionRemoved();
+ if (!putValidator.invalidateRegion()) {
+ throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
+ }
Option opt = NonLockingDataVersion.getInvocationOption();
CacheHelper.removeAll(cache, regionFqn, opt);
}
Modified: core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/PutFromLoadValidator.java
===================================================================
--- core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/PutFromLoadValidator.java 2010-02-23 01:12:57 UTC (rev 18854)
+++ core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/PutFromLoadValidator.java 2010-02-23 02:11:31 UTC (rev 18855)
@@ -30,6 +30,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -46,6 +47,36 @@
* the potential to store stale data, since the data may have been removed from the
* database and the cache between the time when the data was read from the database
* and the actual call to <code>putFromLoad</code>.
+ * <p>
+ * The expected usage of this class by a thread that read the cache and did
+ * not find data is:
+ *
+ * <ol>
+ * <li> Call {@link #registerPendingPut(Object)}</li>
+ * <li> Read the database</li>
+ * <li> Call {@link #acquirePutFromLoadLock(Object)}
+ * <li> if above returns <code>false</code>, the thread should not cache the data;
+ * only if above returns <code>true</code>, put data in the cache and...</li>
+ * <li> then call {@link #releasePutFromLoadLock(Object)}</li>
+ * </ol>
+ * </p>
+ *
+ * <p>
+ * The expected usage by a thread that is taking an action such that any pending
+ * <code>putFromLoad</code> may have stale data and should not cache it is to either
+ * call
+ *
+ * <ul>
+ * <li> {@link #invalidateKey(Object)} (for a single key invalidation)</li>
+ * <li>or {@link #invalidateRegion()} (for a general invalidation all pending puts)</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * This class also supports the concept of "naked puts", which are calls to
+ * {@link #acquirePutFromLoadLock(Object)} without a preceding {@link #registerPendingPut(Object)}
+ * call.
+ * </p>
*
* @author Brian Stansberry
*
@@ -54,21 +85,21 @@
public class PutFromLoadValidator {
/**
* Period in ms after a removal during which a call to
- * {@link #isPutValid(Object)} that hasn't been
+ * {@link #acquirePutFromLoadLock(Object)} that hasn't been
* {@link #registerPendingPut(Object) pre-registered} (aka a "naked put")
* will return false.
*/
- public static final long NAKED_PUT_INVALIDATION_PERIOD = 10 * 1000;
+ public static final long NAKED_PUT_INVALIDATION_PERIOD = 20 * 1000;
- /** Period after which a pending put is placed in the over-age queue */
+ /** Period (in ms) after which a pending put is placed in the over-age queue */
private static final long PENDING_PUT_OVERAGE_PERIOD = 5 * 1000;
- /** Period before which we stop trying to clean out pending puts */
+ /** Period (in ms) before which we stop trying to clean out pending puts */
private static final long PENDING_PUT_RECENT_PERIOD = 2 * 1000;
/**
- * Period after which a pending put is never expected to come in and should
- * be cleaned
+ * Period (in ms) after which a pending put is never expected to come in
+ * and should be cleaned
*/
private static final long MAX_PENDING_PUT_DELAY = 2 * 60 * 1000;
@@ -128,7 +159,7 @@
* Creates a new PutFromLoadValidator.
*
* @param transactionManager
- * transaction manager to use to associated changes with a
+ * transaction manager to use to associate changes with a
* transaction; may be <code>null</code>
*/
public PutFromLoadValidator(TransactionManager transactionManager) {
@@ -153,41 +184,147 @@
// ----------------------------------------------------------------- Public
- public boolean isPutValid(Object key) {
+ /**
+ * Acquire a lock giving the calling thread the right to put data in the
+ * cache for the given key.
+ * <p>
+ * <strong>NOTE:</strong> A call to this method that returns <code>true</code>
+ * should always be matched with a call to {@link #releasePutFromLoadLock(Object)}.
+ * </p>
+ *
+ * @param key the key
+ *
+ * @return <code>true</code> if the lock is acquired and the cache put
+ * can proceed; <code>false</code> if the data should not be cached
+ */
+ public boolean acquirePutFromLoadLock(Object key) {
+
boolean valid = false;
+ boolean locked = false;
long now = System.currentTimeMillis();
- PendingPutMap pending = pendingPuts.get(key);
- if (pending != null) {
- synchronized (pending) {
- PendingPut toCancel = pending.remove(getOwnerForPut());
- valid = toCancel != null;
- if (valid) {
- toCancel.completed = true;
- if (pending.size() == 0) {
- pendingPuts.remove(key);
+ // Important: Do cleanup before we acquire any locks so we
+ // don't deadlock with invalidateRegion
+ cleanOutdatedPendingPuts(now, true);
+
+ try {
+ PendingPutMap pending = pendingPuts.get(key);
+ if (pending != null) {
+ locked = pending.acquireLock(100, TimeUnit.MILLISECONDS);
+ if (locked) {
+ try {
+ PendingPut toCancel = pending.remove(getOwnerForPut());
+ if (toCancel != null) {
+ valid = !toCancel.completed;
+ toCancel.completed = true;
+ }
}
+ finally {
+ if (!valid) {
+ pending.releaseLock();
+ locked = false;
+ }
+ }
}
}
+ else {
+ // Key wasn't in pendingPuts, so either this is a "naked put"
+ // or regionRemoved has been called. Check if we can proceed
+ if (now > invalidationTimestamp) {
+ Long removedTime = recentRemovals.get(key);
+ if (removedTime == null || now > removedTime.longValue()) {
+ // It's legal to proceed. But we have to record this key
+ // in pendingPuts so releasePutFromLoadLock can find it.
+ // To do this we basically simulate a normal "register
+ // then acquire lock" pattern
+ registerPendingPut(key);
+ locked = acquirePutFromLoadLock(key);
+ valid = locked;
+ }
+ }
+ }
}
-
- if (!valid) {
- if (now > invalidationTimestamp) {
- Long removedTime = recentRemovals.get(key);
- if (removedTime == null || now > removedTime.longValue()) {
- valid = true;
+ catch (Throwable t) {
+
+ valid = false;
+
+ if (locked) {
+ PendingPutMap toRelease = pendingPuts.get(key);
+ if (toRelease != null) {
+ toRelease.releaseLock();
}
}
+
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ }
+ else if (t instanceof Error) {
+ throw (Error) t;
+ }
+ else {
+ throw new RuntimeException(t);
+ }
}
-
- cleanOutdatedPendingPuts(now, true);
-
+
return valid;
}
+
+ /**
+ * Releases the lock previously obtained by a call to
+ * {@link #acquirePutFromLoadLock(Object)} that returned <code>true</code>.
+ *
+ * @param key the key
+ */
+ public void releasePutFromLoadLock(Object key) {
+ PendingPutMap pending = pendingPuts.get(key);
+ if (pending != null) {
+ if (pending.size() == 0) {
+ pendingPuts.remove(key);
+ }
+ pending.releaseLock();
+ }
+ }
- public void keyRemoved(Object key) {
+ /**
+ * Invalidates any {@link #registerPendingPut(Object) previously registered pending puts}
+ * ensuring a subsequent call to {@link #acquirePutFromLoadLock(Object)} will
+ * return <code>false</code>.
+ * <p>
+ * This method will block until any concurrent thread that has
+ * {@link #acquirePutFromLoadLock(Object) acquired the putFromLoad lock} for
+ * the given key has released the lock. This allows the caller to be certain
+ * the putFromLoad will not execute after this method returns, possibly
+ * caching stale data.
+ * </p>
+ *
+ * @param key key identifying data whose pending puts should be invalidated
+ *
+ * @return <code>true</code> if the invalidation was successful; <code>false</code>
+ * if a problem occured (which the caller should treat as an
+ * exception condition)
+ */
+ public boolean invalidateKey(Object key) {
+
+ boolean success = true;
+
// Invalidate any pending puts
- pendingPuts.remove(key);
+ PendingPutMap pending = pendingPuts.get(key);
+ if (pending != null) {
+ // This lock should be available very quickly, but we'll be
+ // very patient waiting for it as callers should treat not
+ // acquiring it as an exception condition
+ if (pending.acquireLock(60, TimeUnit.SECONDS)) {
+ try {
+ pending.invalidate();
+ }
+ finally {
+ pending.releaseLock();
+ }
+ }
+ else {
+ success = false;
+ }
+ }
// Record when this occurred to invalidate later naked puts
RecentRemoval removal = new RecentRemoval(key,
@@ -224,55 +361,96 @@
}
}
}
+
+ return success;
}
- public void regionRemoved() {
+ /**
+ * Invalidates all {@link #registerPendingPut(Object) previously registered pending puts}
+ * ensuring a subsequent call to {@link #acquirePutFromLoadLock(Object)} will
+ * return <code>false</code>.
+ * <p>
+ * This method will block until any concurrent thread that has
+ * {@link #acquirePutFromLoadLock(Object) acquired the putFromLoad lock} for
+ * the any key has released the lock. This allows the caller to be certain
+ * the putFromLoad will not execute after this method returns, possibly
+ * caching stale data.
+ * </p>
+ *
+ * @return <code>true</code> if the invalidation was successful; <code>false</code>
+ * if a problem occured (which the caller should treat as an
+ * exception condition)
+ */
+ public boolean invalidateRegion() {
+
+ boolean ok = false;
invalidationTimestamp = System.currentTimeMillis()
+ this.nakedPutInvalidationPeriod;
- pendingLock.lock();
+
try {
+
+ // Acquire the lock for each entry to ensure any ongoing
+ // work associated with it is completed before we return
+ for (PendingPutMap entry : pendingPuts.values()) {
+ if (entry.acquireLock(60, TimeUnit.SECONDS)) {
+ try {
+ entry.invalidate();
+ }
+ finally {
+ entry.releaseLock();
+ }
+ }
+ else {
+ ok = false;
+ }
+ }
+
removalsLock.lock();
try {
- pendingPuts.clear();
- pendingQueue.clear();
- overagePendingQueue.clear();
recentRemovals.clear();
- removalsQueue.clear();
- earliestRemovalTimestamp = invalidationTimestamp;
+ removalsQueue.clear();
+
+ ok = true;
} finally {
removalsLock.unlock();
}
- } finally {
- pendingLock.unlock();
}
+ catch (Exception e) {
+ ok = false;
+ }
+ finally {
+ earliestRemovalTimestamp = invalidationTimestamp;
+ }
+
+ return ok;
}
/**
* Notifies this validator that it is expected that a database read followed
- * by a subsequent {@link #isPutValid(Object)} call will occur. The intent
+ * by a subsequent {@link #acquirePutFromLoadLock(Object)} call will occur. The intent
* is this method would be called following a cache miss wherein it is
* expected that a database read plus cache put will occur. Calling this
* method allows the validator to treat the subsequent
- * <code>isPutValid</code> as if the database read occurred when this method
+ * <code>acquirePutFromLoadLock</code> as if the database read occurred when this method
* was invoked. This allows the validator to compare the timestamp of this
* call against the timestamp of subsequent removal notifications. A put
* that occurs without this call preceding it is "naked"; i.e the validator
* must assume the put is not valid if any relevant removal has occurred
* within {@link #NAKED_PUT_INVALIDATION_PERIOD} milliseconds.
*
- * @param key
- * key that will be used for subsequent put
+ * @param key key that will be used for subsequent cache put
*/
public void registerPendingPut(Object key) {
PendingPut pendingPut = new PendingPut(key, getOwnerForPut());
- PendingPutMap pendingForKey = new PendingPutMap();
- synchronized (pendingForKey) {
- for (;;) {
- PendingPutMap existing = pendingPuts.putIfAbsent(key,
- pendingForKey);
- if (existing != null && existing != pendingForKey) {
- synchronized (existing) {
+ PendingPutMap pendingForKey = new PendingPutMap(pendingPut);
+
+ for (;;) {
+ PendingPutMap existing = pendingPuts.putIfAbsent(key,
+ pendingForKey);
+ if (existing != null) {
+ if (existing.acquireLock(10, TimeUnit.SECONDS)) {
+ try {
existing.put(pendingPut);
PendingPutMap doublecheck = pendingPuts.putIfAbsent(
key, existing);
@@ -281,10 +459,17 @@
}
// else we hit a race and need to loop to try again
}
- } else {
- pendingForKey.put(pendingPut);
+ finally {
+ existing.releaseLock();
+ }
+ }
+ else {
+ // Can't get the lock; when we come back we'll be a "naked put"
break;
}
+ } else {
+ // normal case
+ break;
}
}
@@ -343,7 +528,9 @@
pendingLock.lock();
try {
pendingQueue.add(new WeakReference<PendingPut>(pendingPut));
- cleanOutdatedPendingPuts(pendingPut.timestamp, false);
+ if (pendingQueue.size() > 1) {
+ cleanOutdatedPendingPuts(pendingPut.timestamp, false);
+ }
} finally {
pendingLock.unlock();
}
@@ -356,9 +543,7 @@
pendingLock.lock();
}
try {
-
// Clean items out of the basic queue
-
long overaged = now - this.pendingPutOveragePeriod;
long recent = now - this.pendingPutRecentPeriod;
@@ -411,31 +596,62 @@
if (toClean != null) {
PendingPutMap map = pendingPuts.get(toClean.key);
if (map != null) {
- synchronized (map) {
- PendingPut cleaned = map.remove(toClean.owner);
- if (toClean.equals(cleaned) == false) {
- // Oops. Restore it.
- map.put(cleaned);
- } else if (map.size() == 0) {
- pendingPuts.remove(toClean.key);
+ if (map.acquireLock(100, TimeUnit.MILLISECONDS)) {
+ try {
+ PendingPut cleaned = map.remove(toClean.owner);
+ if (toClean.equals(cleaned) == false) {
+ // Oops. Restore it.
+ map.put(cleaned);
+ } else if (map.size() == 0) {
+ pendingPuts.remove(toClean.key);
+ }
}
+ finally {
+ map.releaseLock();
+ }
}
+ else {
+ // Something's gone wrong and the lock isn't being released.
+ // We removed toClean from the queue and need to restore it
+ // TODO this is pretty dodgy
+ restorePendingPut(toClean);
+ }
}
}
}
+
+ private void restorePendingPut(PendingPut toRestore) {
+ pendingLock.lock();
+ try {
+ // Give it a new lease on life so it's not out of order. We could
+ // scan the queue and put toRestore back at the front, but then
+ // we'll just immediately try removing it again; instead we
+ // let it cycle through the queue again
+ toRestore.refresh();
+ pendingQueue.add(new WeakReference<PendingPut>(toRestore));
+ }
+ finally {
+ pendingLock.unlock();
+ }
+ }
/**
* Lazy-initialization map for PendingPut. Optimized for the expected usual
* case where only a single put is pending for a given key.
*
* This class is NOT THREAD SAFE. All operations on it must be performed
- * with the object monitor held.
+ * with the lock held.
*/
private static class PendingPutMap {
private PendingPut singlePendingPut;
private Map<Object, PendingPut> fullMap;
-
+ private final Lock lock = new ReentrantLock();
+
+ PendingPutMap(PendingPut singleItem) {
+ this.singlePendingPut = singleItem;
+ }
+
public void put(PendingPut pendingPut) {
if (singlePendingPut == null) {
if (fullMap == null) {
@@ -471,18 +687,46 @@
return fullMap == null ? (singlePendingPut == null ? 0 : 1)
: fullMap.size();
}
+
+ public boolean acquireLock(long time, TimeUnit unit) {
+ try {
+ return lock.tryLock(time, unit);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return false;
+ }
+ }
+
+ public void releaseLock() {
+ lock.unlock();
+ }
+
+ public void invalidate() {
+ if (singlePendingPut != null) {
+ singlePendingPut.completed = true;
+ }
+ else if (fullMap != null) {
+ for (PendingPut pp : fullMap.values()) {
+ pp.completed = true;
+ }
+ }
+ }
}
private static class PendingPut {
private final Object key;
private final Object owner;
- private final long timestamp = System.currentTimeMillis();
+ private long timestamp = System.currentTimeMillis();
private volatile boolean completed;
private PendingPut(Object key, Object owner) {
this.key = key;
this.owner = owner;
}
+
+ private void refresh() {
+ timestamp = System.currentTimeMillis();
+ }
}
Modified: core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/TransactionalAccessDelegate.java
===================================================================
--- core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/TransactionalAccessDelegate.java 2010-02-23 01:12:57 UTC (rev 18854)
+++ core/trunk/cache-jbosscache/src/main/java/org/hibernate/cache/jbc/access/TransactionalAccessDelegate.java 2010-02-23 02:11:31 UTC (rev 18855)
@@ -83,12 +83,17 @@
if (!region.checkValid())
return false;
- if (!putValidator.isPutValid(key))
+ if (!putValidator.acquirePutFromLoadLock(key))
return false;
- region.ensureRegionRootExists();
-
- return CacheHelper.putForExternalRead(cache, regionFqn, key, value);
+ try {
+ region.ensureRegionRootExists();
+
+ return CacheHelper.putForExternalRead(cache, regionFqn, key, value);
+ }
+ finally {
+ putValidator.releasePutFromLoadLock(key);
+ }
}
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
@@ -97,15 +102,20 @@
if (!region.checkValid())
return false;
- if (!putValidator.isPutValid(key))
+ if (!putValidator.acquirePutFromLoadLock(key))
return false;
-
- region.ensureRegionRootExists();
-
- // We ignore minimalPutOverride. JBossCache putForExternalRead is
- // already about as minimal as we can get; it will promptly return
- // if it discovers that the node we want to write to already exists
- return CacheHelper.putForExternalRead(cache, regionFqn, key, value);
+
+ try {
+ region.ensureRegionRootExists();
+
+ // We ignore minimalPutOverride. JBossCache putForExternalRead is
+ // already about as minimal as we can get; it will promptly return
+ // if it discovers that the node we want to write to already exists
+ return CacheHelper.putForExternalRead(cache, regionFqn, key, value);
+ }
+ finally {
+ putValidator.releasePutFromLoadLock(key);
+ }
}
public SoftLock lockItem(Object key, Object version) throws CacheException {
@@ -163,7 +173,9 @@
public void remove(Object key) throws CacheException {
- putValidator.keyRemoved(key);
+ if (!putValidator.invalidateKey(key)) {
+ throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
+ }
// We remove whether or not the region is valid. Other nodes
// may have already restored the region so they need to
@@ -175,13 +187,17 @@
}
public void removeAll() throws CacheException {
- putValidator.regionRemoved();
+ if (!putValidator.invalidateRegion()) {
+ throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
+ }
CacheHelper.removeAll(cache, regionFqn);
}
public void evict(Object key) throws CacheException {
- putValidator.keyRemoved(key);
+ if (!putValidator.invalidateKey(key)) {
+ throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
+ }
region.ensureRegionRootExists();
@@ -189,7 +205,10 @@
}
public void evictAll() throws CacheException {
- putValidator.regionRemoved();
+ if (!putValidator.invalidateRegion()) {
+ throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
+ }
+
Transaction tx = region.suspend();
try {
region.ensureRegionRootExists();
Modified: core/trunk/cache-jbosscache/src/test/java/org/hibernate/test/cache/jbc/access/PutFromLoadValidatorUnitTestCase.java
===================================================================
--- core/trunk/cache-jbosscache/src/test/java/org/hibernate/test/cache/jbc/access/PutFromLoadValidatorUnitTestCase.java 2010-02-23 01:12:57 UTC (rev 18854)
+++ core/trunk/cache-jbosscache/src/test/java/org/hibernate/test/cache/jbc/access/PutFromLoadValidatorUnitTestCase.java 2010-02-23 02:11:31 UTC (rev 18855)
@@ -23,11 +23,15 @@
*/
package org.hibernate.test.cache.jbc.access;
+import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
@@ -87,7 +91,7 @@
if (transactional) {
tm.begin();
}
- assertTrue(testee.isPutValid(KEY1));
+ assertTrue(testee.acquirePutFromLoadLock(KEY1));
}
public void testRegisteredPut() throws Exception {
@@ -105,7 +109,16 @@
tm.begin();
}
testee.registerPendingPut(KEY1);
- assertTrue(testee.isPutValid(KEY1));
+
+ boolean lockable = testee.acquirePutFromLoadLock(KEY1);
+ try {
+ assertTrue(lockable);
+ }
+ finally {
+ if (lockable) {
+ testee.releasePutFromLoadLock(KEY1);
+ }
+ }
}
public void testNakedPutAfterKeyRemoval() throws Exception {
@@ -129,14 +142,23 @@
PutFromLoadValidator testee = new PutFromLoadValidator(
transactional ? tm : null);
if (removeRegion) {
- testee.regionRemoved();
+ testee.invalidateRegion();
} else {
- testee.keyRemoved(KEY1);
+ testee.invalidateKey(KEY1);
}
if (transactional) {
tm.begin();
}
- assertFalse(testee.isPutValid(KEY1));
+
+ boolean lockable = testee.acquirePutFromLoadLock(KEY1);
+ try {
+ assertFalse(lockable);
+ }
+ finally {
+ if (lockable) {
+ testee.releasePutFromLoadLock(KEY1);
+ }
+ }
}
@@ -163,15 +185,24 @@
PutFromLoadValidator testee = new PutFromLoadValidator(
transactional ? tm : null);
if (removeRegion) {
- testee.regionRemoved();
+ testee.invalidateRegion();
} else {
- testee.keyRemoved(KEY1);
+ testee.invalidateKey(KEY1);
}
if (transactional) {
tm.begin();
}
testee.registerPendingPut(KEY1);
- assertTrue(testee.isPutValid(KEY1));
+
+ boolean lockable = testee.acquirePutFromLoadLock(KEY1);
+ try {
+ assertTrue(lockable);
+ }
+ finally {
+ if (lockable) {
+ testee.releasePutFromLoadLock(KEY1);
+ }
+ }
}
public void testRegisteredPutWithInterveningKeyRemoval() throws Exception {
@@ -202,11 +233,20 @@
}
testee.registerPendingPut(KEY1);
if (removeRegion) {
- testee.regionRemoved();
+ testee.invalidateRegion();
} else {
- testee.keyRemoved(KEY1);
+ testee.invalidateKey(KEY1);
}
- assertFalse(testee.isPutValid(KEY1));
+
+ boolean lockable = testee.acquirePutFromLoadLock(KEY1);
+ try {
+ assertFalse(lockable);
+ }
+ finally {
+ if (lockable) {
+ testee.releasePutFromLoadLock(KEY1);
+ }
+ }
}
public void testDelayedNakedPutAfterKeyRemoval() throws Exception {
@@ -232,15 +272,24 @@
PutFromLoadValidator testee = new TestValidator(transactional ? tm
: null, 100, 1000, 500, 10000);
if (removeRegion) {
- testee.regionRemoved();
+ testee.invalidateRegion();
} else {
- testee.keyRemoved(KEY1);
+ testee.invalidateKey(KEY1);
}
if (transactional) {
tm.begin();
}
Thread.sleep(110);
- assertTrue(testee.isPutValid(KEY1));
+
+ boolean lockable = testee.acquirePutFromLoadLock(KEY1);
+ try {
+ assertTrue(lockable);
+ }
+ finally {
+ if (lockable) {
+ testee.releasePutFromLoadLock(KEY1);
+ }
+ }
}
@@ -268,8 +317,13 @@
testee.registerPendingPut(KEY1);
registeredLatch.countDown();
registeredLatch.await(5, TimeUnit.SECONDS);
- if (testee.isPutValid(KEY1)) {
- success.incrementAndGet();
+ if (testee.acquirePutFromLoadLock(KEY1)) {
+ try {
+ success.incrementAndGet();
+ }
+ finally {
+ testee.releasePutFromLoadLock(KEY1);
+ }
}
finishedLatch.countDown();
}
@@ -284,7 +338,7 @@
// Start with a removal so the "isPutValid" calls will fail if
// any of the concurrent activity isn't handled properly
- testee.regionRemoved();
+ testee.invalidateRegion();
// Do the registration + isPutValid calls
executor.execute(r);
@@ -303,13 +357,13 @@
*/
public void testRemovalCleanup() throws Exception {
TestValidator testee = new TestValidator(null, 200, 1000, 500, 10000);
- testee.keyRemoved("KEY1");
- testee.keyRemoved("KEY2");
+ testee.invalidateKey("KEY1");
+ testee.invalidateKey("KEY2");
Thread.sleep(210);
assertEquals(2, testee.getRemovalQueueLength());
- testee.keyRemoved("KEY1");
+ testee.invalidateKey("KEY1");
assertEquals(2, testee.getRemovalQueueLength());
- testee.keyRemoved("KEY2");
+ testee.invalidateKey("KEY2");
assertEquals(2, testee.getRemovalQueueLength());
}
@@ -324,7 +378,7 @@
// Start with a regionRemoval so we can confirm at the end that all
// registrations have been cleaned out
- testee.regionRemoved();
+ testee.invalidateRegion();
testee.registerPendingPut("1");
testee.registerPendingPut("2");
@@ -332,8 +386,10 @@
testee.registerPendingPut("4");
testee.registerPendingPut("5");
testee.registerPendingPut("6");
- testee.isPutValid("6");
- testee.isPutValid("2");
+ testee.acquirePutFromLoadLock("6");
+ testee.releasePutFromLoadLock("6");
+ testee.acquirePutFromLoadLock("2");
+ testee.releasePutFromLoadLock("2");
// ppq = [1,2(c),3,4,5,6(c)]
assertEquals(6, testee.getPendingPutQueueLength());
assertEquals(0, testee.getOveragePendingPutQueueLength());
@@ -358,7 +414,8 @@
// Sleep past "maxPendingPutDelay"
Thread.sleep(310);
- testee.isPutValid("3");
+ testee.acquirePutFromLoadLock("3");
+ testee.releasePutFromLoadLock("3");
// White box -- should have cleaned out 1 (overage) and
// moved 7 to overage queue
// oppq = [3(c),4,5,7] ppq=[8]
@@ -380,21 +437,116 @@
// Validate that only expected items can do puts, thus indirectly
// proving the others have been cleaned out of pendingPuts map
- assertFalse(testee.isPutValid("1"));
+ boolean locked = testee.acquirePutFromLoadLock("1");
+ if (locked) {
+ testee.releasePutFromLoadLock("1");
+ }
+ assertFalse(locked);
// 5 was overage, so should have been cleaned
assertEquals(2, testee.getOveragePendingPutQueueLength());
- assertFalse(testee.isPutValid("2"));
+ locked = testee.acquirePutFromLoadLock("2");
+ if (locked) {
+ testee.releasePutFromLoadLock("1");
+ }
+ assertFalse(locked);
// 7 was overage, so should have been cleaned
assertEquals(1, testee.getOveragePendingPutQueueLength());
- assertFalse(testee.isPutValid("3"));
- assertFalse(testee.isPutValid("4"));
- assertFalse(testee.isPutValid("5"));
- assertFalse(testee.isPutValid("6"));
- assertFalse(testee.isPutValid("7"));
- assertTrue(testee.isPutValid("8"));
+ locked = testee.acquirePutFromLoadLock("3");
+ if (locked) {
+ testee.releasePutFromLoadLock("1");
+ }
+ assertFalse(locked);
+ locked = testee.acquirePutFromLoadLock("4");
+ if (locked) {
+ testee.releasePutFromLoadLock("1");
+ }
+ assertFalse(locked);
+ locked = testee.acquirePutFromLoadLock("5");
+ if (locked) {
+ testee.releasePutFromLoadLock("1");
+ }
+ assertFalse(locked);
+ locked = testee.acquirePutFromLoadLock("1");
+ if (locked) {
+ testee.releasePutFromLoadLock("1");
+ }
+ assertFalse(testee.acquirePutFromLoadLock("6"));
+ locked = testee.acquirePutFromLoadLock("7");
+ if (locked) {
+ testee.releasePutFromLoadLock("1");
+ }
+ assertFalse(locked);
+ assertTrue(testee.acquirePutFromLoadLock("8"));
+ testee.releasePutFromLoadLock("8");
tm.resume(tx);
- assertTrue(testee.isPutValid("7"));
+ assertTrue(testee.acquirePutFromLoadLock("7"));
+ testee.releasePutFromLoadLock("7");
}
+
+ public void testInvalidateKeyBlocksForInProgressPut() throws Exception {
+ invalidationBlocksForInProgressPutTest(true);
+ }
+
+ public void testInvalidateRegionBlocksForInProgressPut() throws Exception {
+ invalidationBlocksForInProgressPutTest(false);
+ }
+
+ private void invalidationBlocksForInProgressPutTest(final boolean keyOnly) throws Exception {
+ final PutFromLoadValidator testee = new PutFromLoadValidator(null);
+ final CountDownLatch removeLatch = new CountDownLatch(1);
+ final CountDownLatch pferLatch = new CountDownLatch(1);
+ final AtomicReference<Object> cache = new AtomicReference<Object>("INITIAL");
+
+ Callable<Boolean> pferCallable = new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ testee.registerPendingPut(KEY1);
+ if (testee.acquirePutFromLoadLock(KEY1)) {
+ try {
+ removeLatch.countDown();
+ pferLatch.await();
+ cache.set("PFER");
+ return Boolean.TRUE;
+ }
+ finally {
+ testee.releasePutFromLoadLock(KEY1);
+ }
+ }
+ return Boolean.FALSE;
+ }
+ };
+
+ Callable<Void> invalidateCallable = new Callable<Void>() {
+ public Void call() throws Exception {
+ removeLatch.await();
+ if (keyOnly) {
+ testee.invalidateKey(KEY1);
+ }
+ else {
+ testee.invalidateRegion();
+ }
+ cache.set(null);
+ return null;
+ }
+ };
+
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ Future<Boolean> pferFuture = executorService.submit(pferCallable);
+ Future<Void> invalidateFuture = executorService.submit(invalidateCallable);
+
+ try {
+ invalidateFuture.get(1, TimeUnit.SECONDS);
+ fail("invalidateFuture did not block");
+ }
+ catch (TimeoutException good) {}
+
+ pferLatch.countDown();
+
+ assertTrue(pferFuture.get(5, TimeUnit.SECONDS));
+ invalidateFuture.get(5, TimeUnit.SECONDS);
+
+ assertNull(cache.get());
+
+ }
private static class TestValidator extends PutFromLoadValidator {
@@ -408,19 +560,16 @@
@Override
public int getOveragePendingPutQueueLength() {
- // TODO Auto-generated method stub
return super.getOveragePendingPutQueueLength();
}
@Override
public int getPendingPutQueueLength() {
- // TODO Auto-generated method stub
return super.getPendingPutQueueLength();
}
@Override
public int getRemovalQueueLength() {
- // TODO Auto-generated method stub
return super.getRemovalQueueLength();
}
14 years, 2 months
Hibernate SVN: r18854 - core/trunk/core/src/main/java/org/hibernate.
by hibernate-commits@lists.jboss.org
Author: smarlow(a)redhat.com
Date: 2010-02-22 20:12:57 -0500 (Mon, 22 Feb 2010)
New Revision: 18854
Modified:
core/trunk/core/src/main/java/org/hibernate/QueryTimeoutException.java
Log:
HHH-4662 Implement javax.persistence.query.timeout
Modified: core/trunk/core/src/main/java/org/hibernate/QueryTimeoutException.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/QueryTimeoutException.java 2010-02-23 01:06:16 UTC (rev 18853)
+++ core/trunk/core/src/main/java/org/hibernate/QueryTimeoutException.java 2010-02-23 01:12:57 UTC (rev 18854)
@@ -35,26 +35,12 @@
public class QueryTimeoutException extends JDBCException {
- Object entity;
+ public QueryTimeoutException( String s, JDBCException je, String sql ) {
+ super(s, je.getSQLException(), sql);
+ }
-
- public QueryTimeoutException( String s, JDBCException je, Object entity ) {
- super(s, je.getSQLException());
- this.entity = entity;
- }
-
- public QueryTimeoutException( String s, SQLException se, Object entity ) {
- super(s, se);
- this.entity = entity;
- }
-
public QueryTimeoutException( String s, SQLException se, String sql ) {
- super(s, se, sql);
- this.entity = null;
- }
-
- public Object getEntity() {
- return entity;
+ super(s, se, sql);
}
}
14 years, 2 months
Hibernate SVN: r18853 - core/trunk/core/src/main/java/org/hibernate.
by hibernate-commits@lists.jboss.org
Author: smarlow(a)redhat.com
Date: 2010-02-22 20:06:16 -0500 (Mon, 22 Feb 2010)
New Revision: 18853
Added:
core/trunk/core/src/main/java/org/hibernate/QueryTimeoutException.java
Log:
HHH-4662 Implement javax.persistence.query.timeout
Added: core/trunk/core/src/main/java/org/hibernate/QueryTimeoutException.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/QueryTimeoutException.java (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/QueryTimeoutException.java 2010-02-23 01:06:16 UTC (rev 18853)
@@ -0,0 +1,60 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+package org.hibernate;
+
+import java.sql.SQLException;
+
+/**
+ *
+ * Thrown when a database query timeout occurs.
+ *
+ * @author Scott Marlow
+ */
+
+public class QueryTimeoutException extends JDBCException {
+
+ Object entity;
+
+
+ public QueryTimeoutException( String s, JDBCException je, Object entity ) {
+ super(s, je.getSQLException());
+ this.entity = entity;
+ }
+
+ public QueryTimeoutException( String s, SQLException se, Object entity ) {
+ super(s, se);
+ this.entity = entity;
+ }
+
+ public QueryTimeoutException( String s, SQLException se, String sql ) {
+ super(s, se, sql);
+ this.entity = null;
+ }
+
+ public Object getEntity() {
+ return entity;
+ }
+
+}
14 years, 2 months
Hibernate SVN: r18852 - in core/trunk: core/src/main/java/org/hibernate/exception and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: smarlow(a)redhat.com
Date: 2010-02-22 18:27:16 -0500 (Mon, 22 Feb 2010)
New Revision: 18852
Modified:
core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java
core/trunk/core/src/main/java/org/hibernate/exception/SQLStateConverter.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryHints.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
Log:
HHH-4662 Implement javax.persistence.query.timeout
Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java 2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java 2010-02-22 23:27:16 UTC (rev 18852)
@@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
@@ -69,7 +69,7 @@
queryName,
getBoolean( queryName, "org.hibernate.cacheable", hints ),
getString( queryName, "org.hibernate.cacheRegion", hints ),
- getInteger( queryName, "org.hibernate.timeout", hints ),
+ getTimeout( queryName, hints ),
getInteger( queryName, "org.hibernate.fetchSize", hints ),
getFlushMode( queryName, hints ),
getCacheMode( queryName, hints ),
@@ -105,7 +105,7 @@
null,
getBoolean( queryName, "org.hibernate.cacheable", hints ),
getString( queryName, "org.hibernate.cacheRegion", hints ),
- getInteger( queryName, "org.hibernate.timeout", hints ),
+ getTimeout( queryName, hints ),
getInteger( queryName, "org.hibernate.fetchSize", hints ),
getFlushMode( queryName, hints ),
getCacheMode( queryName, hints ),
@@ -126,7 +126,7 @@
null,
getBoolean( queryName, "org.hibernate.cacheable", hints ),
getString( queryName, "org.hibernate.cacheRegion", hints ),
- getInteger( queryName, "org.hibernate.timeout", hints ),
+ getTimeout( queryName, hints ),
getInteger( queryName, "org.hibernate.fetchSize", hints ),
getFlushMode( queryName, hints ),
getCacheMode( queryName, hints ),
@@ -407,4 +407,18 @@
}
return null;
}
+
+ private static Integer getTimeout(String queryName, QueryHint[] hints) {
+ Integer timeout = getInteger( queryName, "javax.persistence.query.timeout", hints );
+
+ if ( timeout != null ) {
+ // convert milliseconds to seconds
+ timeout = new Integer ((int)Math.round(timeout.doubleValue() / 1000.0 ) );
+ }
+ else {
+ // timeout is already in seconds
+ timeout = getInteger( queryName, "org.hibernate.timeout", hints );
+ }
+ return timeout;
+ }
}
Modified: core/trunk/core/src/main/java/org/hibernate/exception/SQLStateConverter.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/exception/SQLStateConverter.java 2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/core/src/main/java/org/hibernate/exception/SQLStateConverter.java 2010-02-22 23:27:16 UTC (rev 18852)
@@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
@@ -26,6 +26,7 @@
import org.hibernate.JDBCException;
import org.hibernate.PessimisticLockException;
+import org.hibernate.QueryTimeoutException;
import java.sql.SQLException;
import java.util.HashSet;
@@ -115,6 +116,13 @@
// Derby "A lock could not be obtained within the time requested."
return new PessimisticLockException( message, sqlException, sql );
}
+
+ // MySQL Query execution was interrupted
+ if ( "70100".equals( sqlState ) ||
+ // Oracle user requested cancel of current operation
+ "72000".equals( sqlState ) ) {
+ throw new QueryTimeoutException( message, sqlException, sql );
+ }
}
return handledNonSpecificException( sqlException, message, sql );
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java 2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java 2010-02-22 23:27:16 UTC (rev 18852)
@@ -1130,6 +1130,11 @@
handlePersistenceException( converted );
return converted;
}
+ else if ( e instanceof org.hibernate.QueryTimeoutException ) {
+ QueryTimeoutException converted = new QueryTimeoutException(e.getMessage(), e);
+ handlePersistenceException( converted );
+ return converted;
+ }
else if ( e instanceof ObjectNotFoundException ) {
EntityNotFoundException converted = new EntityNotFoundException( e.getMessage() );
handlePersistenceException( converted );
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java 2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java 2010-02-22 23:27:16 UTC (rev 18852)
@@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
+ * Copyright (c) 2010 by Red Hat Inc and/or its affiliates or by
* third-party contributors as indicated by either @author tags or express
* copyright attribution statements applied by the authors. All
* third-party contributions are distributed under license by Red Hat Inc.
@@ -50,6 +50,7 @@
import static org.hibernate.ejb.QueryHints.HINT_FLUSH_MODE;
import static org.hibernate.ejb.QueryHints.HINT_READONLY;
import static org.hibernate.ejb.QueryHints.HINT_TIMEOUT;
+import static org.hibernate.ejb.QueryHints.SPEC_HINT_TIMEOUT;
import org.hibernate.ejb.util.CacheModeHelper;
import org.hibernate.ejb.util.ConfigurationHelper;
@@ -204,6 +205,11 @@
if ( HINT_TIMEOUT.equals( hintName ) ) {
applyTimeout( ConfigurationHelper.getInteger( value ) );
}
+ else if ( SPEC_HINT_TIMEOUT.equals( hintName ) ) {
+ // convert milliseconds to seconds
+ int timeout = (int)Math.round(ConfigurationHelper.getInteger( value ).doubleValue() / 1000.0 );
+ applyTimeout( new Integer(timeout) );
+ }
else if ( HINT_COMMENT.equals( hintName ) ) {
applyComment( (String) value );
}
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryHints.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryHints.java 2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryHints.java 2010-02-22 23:27:16 UTC (rev 18852)
@@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
+ * Copyright (c) 2010 by Red Hat Inc and/or its affiliates or by
* third-party contributors as indicated by either @author tags or express
* copyright attribution statements applied by the authors. All
* third-party contributions are distributed under license by Red Hat Inc.
@@ -32,7 +32,12 @@
* @author Steve Ebersole
*/
public class QueryHints {
- public static final String HINT_TIMEOUT = "org.hibernate.timeout";
+ /**
+ * @deprecated HINT_TIMEOUT (org.hibernate.timeout),
+ * instead use SPEC_HINT_TIMEOUT (javax.persistence.query.timeout)
+ */
+ public static final String HINT_TIMEOUT = "org.hibernate.timeout"; // Query timeout in seconds
+ public static final String SPEC_HINT_TIMEOUT = "javax.persistence.query.timeout"; // timeout in milliseconds
public static final String HINT_COMMENT = "org.hibernate.comment";
public static final String HINT_FETCH_SIZE = "org.hibernate.fetchSize";
public static final String HINT_CACHE_REGION = "org.hibernate.cacheRegion";
@@ -46,6 +51,7 @@
private static Set<String> buildHintsSet() {
HashSet<String> hints = new HashSet<String>();
hints.add( HINT_TIMEOUT );
+ hints.add( SPEC_HINT_TIMEOUT );
hints.add( HINT_COMMENT );
hints.add( HINT_FETCH_SIZE );
hints.add( HINT_CACHE_REGION );
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java 2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java 2010-02-22 23:27:16 UTC (rev 18852)
@@ -6,6 +6,7 @@
import javax.persistence.LockTimeoutException;
import javax.persistence.OptimisticLockException;
import javax.persistence.Query;
+import javax.persistence.QueryTimeoutException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -511,8 +512,96 @@
}
}
+ public void testQueryTimeout() throws Exception {
+ EntityManager em = getOrCreateEntityManager();
+ final EntityManager em2 = createIsolatedEntityManager();
+ // TODO: replace dialect instanceof test with a Dialect.hasCapability
+ if ( ! (getDialect() instanceof Oracle10gDialect)) {
+ log.info("skipping testQueryTimeout");
+ return;
+ }
+ Lock lock = new Lock();
+ Thread t = null;
+ FutureTask<Boolean> bgTask = null;
+ final CountDownLatch latch = new CountDownLatch(1);
+ try {
+ lock.setName( "testQueryTimeout" );
+ em.getTransaction().begin();
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.clear();
+
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
+ final Integer id = lock.getId();
+ lock.getName(); // force entity to be read
+ log.info("testQueryTimeout: got write lock");
+
+ bgTask = new FutureTask<Boolean>( new Callable() {
+ public Boolean call() {
+ try {
+ boolean timedOut = false; // true (success) if LockTimeoutException occurred
+ em2.getTransaction().begin();
+ log.info( "testQueryTimeout: (BG) about to read write-locked entity" );
+ // we should block on the following read
+ Lock lock2 = em2.getReference( Lock.class, id );
+ lock2.getName(); // force entity to be read
+ log.info( "testQueryTimeout: (BG) read write-locked entity" );
+ try {
+ // we should block on the following read
+ Query query = em2.createQuery(
+ "select L from Lock_ L where L.id < 10000 ");
+ query.setLockMode( LockModeType.PESSIMISTIC_READ );
+ query.setHint( "javax.persistence.query.timeout", new Integer(500) ); // 1 sec timeout
+ List<Lock> resultList = query.getResultList();
+ String name = resultList.get(0).getName(); // force entity to be read
+ log.info( "testQueryTimeout: name read =" + name );
+ }
+ catch( QueryTimeoutException e) {
+ // success
+ log.info( "testQueryTimeout: (BG) got expected timeout exception" );
+ timedOut = true;
+ }
+ catch ( Throwable e) {
+ log.info( "testQueryTimeout: Expected LockTimeoutException but got unexpected exception", e );
+ }
+ em2.getTransaction().commit();
+ return new Boolean( timedOut );
+ }
+ finally {
+ latch.countDown(); // signal that we finished
+ }
+ }
+ } );
+ t = new Thread(bgTask);
+ t.setDaemon( true );
+ t.setName( "testQueryTimeout (bg)" );
+ t.start();
+ boolean latchSet = latch.await( 10, TimeUnit.SECONDS ); // should return quickly on success
+ assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
+ assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
+ em.getTransaction().commit();
+ }
+ finally {
+ if ( em.getTransaction().isActive() ) {
+ em.getTransaction().rollback();
+ }
+ if ( t != null) { // wait for background thread to finish before deleting entity
+ t.join();
+ }
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.remove( lock );
+ em.getTransaction().commit();
+ em.close();
+ em2.close();
+ }
+ }
+
+
public Class[] getAnnotatedClasses() {
return new Class[]{
Lock.class,
14 years, 2 months
Hibernate SVN: r18851 - jpamodelgen/trunk/src/main/docbook/en-US.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-02-22 16:59:43 -0500 (Mon, 22 Feb 2010)
New Revision: 18851
Modified:
jpamodelgen/trunk/src/main/docbook/en-US/master.xml
Log:
METAGEN-27
Modified: jpamodelgen/trunk/src/main/docbook/en-US/master.xml
===================================================================
--- jpamodelgen/trunk/src/main/docbook/en-US/master.xml 2010-02-22 21:17:12 UTC (rev 18850)
+++ jpamodelgen/trunk/src/main/docbook/en-US/master.xml 2010-02-22 21:59:43 UTC (rev 18851)
@@ -20,7 +20,7 @@
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY versionNumber "1.0.0">
<!ENTITY copyrightYear "2010">
-<!ENTITY copyrightHolder "Red Hat Middleware, LLC.">
+<!ENTITY copyrightHolder "Red Hat Inc.">
]>
<book lang="en">
<bookinfo>
@@ -90,9 +90,8 @@
}</programlisting>
</example>
- <example id="criteria-example" label="">
- <title>Example of typesafe query using the metamodel class
- <classname>Order_</classname></title>
+ <example id="criteria-example">
+ <title>Example of typesafe query</title>
<programlisting>CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
@@ -192,8 +191,8 @@
url="http://repository.jboss.com/">JBoss Maven repository</ulink>
under:</para>
- <example id="maven-dependency" label="">
- <title>Maven dependency for Hibernate Static Metamodel Generator</title>
+ <example id="maven-dependency">
+ <title>Maven dependency </title>
<programlisting><dependency>
<groupId>org.hibernate</groupId>
@@ -412,7 +411,8 @@
url="http://www.netbeans.org/issues/show_bug.cgi?id=111065">111065</ulink>,
<ulink
url="http://www.netbeans.org/issues/show_bug.cgi?id=111293">111293</ulink>
- and <ulink url="???">111294</ulink>.</para>
+ and <ulink
+ url="http://www.netbeans.org/issues/show_bug.cgi?id=111294">111294</ulink>.</para>
</section>
</section>
14 years, 2 months
Hibernate SVN: r18850 - in core/trunk/entitymanager/src: test/java/org/hibernate/ejb/test/exception and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-02-22 16:17:12 -0500 (Mon, 22 Feb 2010)
New Revision: 18850
Added:
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/exception/Instrument.java
Modified:
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/HibernateEntityManagerImplementor.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/exception/ExceptionTest.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/transaction/FlushAndTransactionTest.java
Log:
HHH-4676
* now a transaction is marked for rollback for all RuntimeExceptions not only the CosntraintViolationExcpetion.
* Also updated FlushAndTransactionTest which had invalid assertions.
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java 2010-02-22 16:43:06 UTC (rev 18849)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java 2010-02-22 21:17:12 UTC (rev 18850)
@@ -63,7 +63,6 @@
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
-import javax.validation.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -112,6 +111,7 @@
private static final Logger log = LoggerFactory.getLogger( AbstractEntityManagerImpl.class );
private static final List<String> entityManagerSpecificProperties = new ArrayList<String>();
+
static {
entityManagerSpecificProperties.add( AvailableSettings.LOCK_SCOPE );
entityManagerSpecificProperties.add( AvailableSettings.LOCK_TIMEOUT );
@@ -136,9 +136,9 @@
this.persistenceContextType = type;
this.transactionType = transactionType;
- this.lockOptions = new LockOptions( );
+ this.lockOptions = new LockOptions();
this.properties = new HashMap<String, Object>();
- if(properties != null) {
+ if ( properties != null ) {
for ( String key : entityManagerSpecificProperties ) {
if ( properties.containsKey( key ) ) {
this.properties.put( key, properties.get( key ) );
@@ -159,7 +159,7 @@
private void applyProperties() {
getSession().setFlushMode( ConfigurationHelper.getFlushMode( properties.get( AvailableSettings.FLUSH_MODE ) ) );
- setLockOptions(this.properties, this.lockOptions);
+ setLockOptions( this.properties, this.lockOptions );
getSession().setCacheMode(
CacheModeHelper.interpretCacheMode(
currentCacheStoreMode(),
@@ -172,16 +172,16 @@
return determineCacheRetrieveMode( properties );
}
- private CacheRetrieveMode determineCacheRetrieveMode(Map<String,Object> settings) {
- return (CacheRetrieveMode) settings.get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE );
+ private CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) {
+ return ( CacheRetrieveMode ) settings.get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE );
}
private CacheStoreMode currentCacheStoreMode() {
return determineCacheStoreMode( properties );
}
- private CacheStoreMode determineCacheStoreMode(Map<String,Object> settings) {
- return (CacheStoreMode) properties.get( AvailableSettings.SHARED_CACHE_STORE_MODE );
+ private CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) {
+ return ( CacheStoreMode ) properties.get( AvailableSettings.SHARED_CACHE_STORE_MODE );
}
private void setLockOptions(Map<String, Object> props, LockOptions options) {
@@ -229,19 +229,19 @@
* set.
*/
private void setDefaultProperties() {
- if ( properties.get( AvailableSettings.FLUSH_MODE ) == null) {
+ if ( properties.get( AvailableSettings.FLUSH_MODE ) == null ) {
properties.put( AvailableSettings.FLUSH_MODE, getSession().getFlushMode().toString() );
}
- if ( properties.get( AvailableSettings.LOCK_SCOPE ) == null) {
+ if ( properties.get( AvailableSettings.LOCK_SCOPE ) == null ) {
this.properties.put( AvailableSettings.LOCK_SCOPE, PessimisticLockScope.EXTENDED.name() );
}
- if ( properties.get( AvailableSettings.LOCK_TIMEOUT ) == null) {
+ if ( properties.get( AvailableSettings.LOCK_TIMEOUT ) == null ) {
properties.put( AvailableSettings.LOCK_TIMEOUT, LockOptions.WAIT_FOREVER );
}
- if ( properties.get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE ) == null) {
+ if ( properties.get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE ) == null ) {
properties.put( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.DEFAULT_RETRIEVE_MODE );
}
- if ( properties.get( AvailableSettings.SHARED_CACHE_STORE_MODE ) == null) {
+ if ( properties.get( AvailableSettings.SHARED_CACHE_STORE_MODE ) == null ) {
properties.put( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheModeHelper.DEFAULT_STORE_MODE );
}
}
@@ -261,7 +261,7 @@
if ( hqlQuery.getReturnTypes().length != 1 ) {
throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
}
- if ( ! resultClass.isAssignableFrom( hqlQuery.getReturnTypes()[0].getReturnedClass() ) ) {
+ if ( !resultClass.isAssignableFrom( hqlQuery.getReturnTypes()[0].getReturnedClass() ) ) {
throw new IllegalArgumentException(
"Type specified for TypedQuery [" +
resultClass.getName() +
@@ -290,7 +290,7 @@
// determine if we need a result transformer
List tupleElements = Tuple.class.equals( resultClass )
- ? ( (CompoundSelectionImpl<Tuple>) selection ).getCompoundSelectionItems()
+ ? ( ( CompoundSelectionImpl<Tuple> ) selection ).getCompoundSelectionItems()
: null;
if ( options.getValueHandlers() != null || tupleElements != null ) {
hqlQuery.setResultTransformer(
@@ -321,7 +321,7 @@
valueHandlerResult = tuple;
}
else {
- valueHandlerResult = new Object[ tuple.length ];
+ valueHandlerResult = new Object[tuple.length];
for ( int i = 0; i < tuple.length; i++ ) {
ValueHandlerFactory.ValueHandler valueHandler = valueHandlers.get( i );
valueHandlerResult[i] = valueHandler == null
@@ -352,10 +352,12 @@
public <X> X get(TupleElement<X> tupleElement) {
int index = tupleElements.indexOf( tupleElement );
if ( index < 0 ) {
- throw new IllegalArgumentException( "Requested tuple element did not correspond to element in the result tuple" );
+ throw new IllegalArgumentException(
+ "Requested tuple element did not correspond to element in the result tuple"
+ );
}
// index should be "in range" by nature of size check in ctor
- return (X) tuples[index];
+ return ( X ) tuples[index];
}
public Object get(String alias) {
@@ -364,7 +366,7 @@
alias = alias.trim();
if ( alias.length() > 0 ) {
int i = 0;
- for ( TupleElement selection : (List<TupleElement>) tupleElements ) {
+ for ( TupleElement selection : ( List<TupleElement> ) tupleElements ) {
if ( alias.equals( selection.getAlias() ) ) {
index = i;
break;
@@ -383,7 +385,7 @@
}
public <X> X get(String alias, Class<X> type) {
- return (X) get( alias );
+ return ( X ) get( alias );
}
public Object get(int i) {
@@ -396,7 +398,7 @@
}
public <X> X get(int i, Class<X> type) {
- return (X) get( i );
+ return ( X ) get( i );
}
public Object[] toArray() {
@@ -404,7 +406,7 @@
}
public List<TupleElement<?>> getElements() {
- return (List<TupleElement<?>>) tupleElements;
+ return ( List<TupleElement<?>> ) tupleElements;
}
}
}
@@ -440,7 +442,7 @@
if ( namedQuery.getReturnTypes().length != 1 ) {
throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
}
- if ( ! resultClass.isAssignableFrom( namedQuery.getReturnTypes()[0].getReturnedClass() ) ) {
+ if ( !resultClass.isAssignableFrom( namedQuery.getReturnTypes()[0].getReturnedClass() ) ) {
throw new IllegalArgumentException(
"Type specified for TypedQuery [" +
resultClass.getName() +
@@ -512,19 +514,19 @@
@SuppressWarnings("unchecked")
public <A> A find(Class<A> entityClass, Object primaryKey) {
- return find( entityClass, primaryKey, null, null);
+ return find( entityClass, primaryKey, null, null );
}
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
- return find(entityClass, primaryKey, null, null);
+ return find( entityClass, primaryKey, null, null );
}
@SuppressWarnings("unchecked")
- public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType lockModeType) {
- return find(entityClass, primaryKey, lockModeType, null);
+ public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType lockModeType) {
+ return find( entityClass, primaryKey, lockModeType, null );
}
- public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType lockModeType, Map<String, Object> properties) {
+ public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType lockModeType, Map<String, Object> properties) {
CacheMode previousCacheMode = getSession().getCacheMode();
CacheMode cacheMode = determineAppropriateLocalCacheMode( properties );
LockOptions lockOptions = null;
@@ -536,8 +538,9 @@
getLockRequest( lockModeType, properties )
);
}
- else
+ else {
return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey );
+ }
}
catch ( ObjectDeletedException e ) {
//the spec is silent about people doing remove() find() on the same PC
@@ -557,7 +560,7 @@
throw new IllegalArgumentException( e.getMessage(), e );
}
catch ( HibernateException he ) {
- throw convert( he , lockOptions );
+ throw convert( he, lockOptions );
}
finally {
getSession().setCacheMode( previousCacheMode );
@@ -635,15 +638,15 @@
}
public void refresh(Object entity) {
- refresh(entity, null, null);
+ refresh( entity, null, null );
}
public void refresh(Object entity, Map<String, Object> properties) {
- refresh(entity, null, null);
+ refresh( entity, null, null );
}
public void refresh(Object entity, LockModeType lockModeType) {
- refresh(entity, lockModeType, null);
+ refresh( entity, lockModeType, null );
}
public void refresh(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
@@ -656,16 +659,18 @@
if ( !getSession().contains( entity ) ) {
throw new IllegalArgumentException( "Entity not managed" );
}
- if(lockModeType != null)
- getSession().refresh( entity, (lockOptions = getLockRequest(lockModeType, properties) ) );
- else
+ if ( lockModeType != null ) {
+ getSession().refresh( entity, ( lockOptions = getLockRequest( lockModeType, properties ) ) );
+ }
+ else {
getSession().refresh( entity );
+ }
}
catch ( MappingException e ) {
throw new IllegalArgumentException( e.getMessage(), e );
}
catch ( HibernateException he ) {
- throw convert( he, lockOptions);
+ throw convert( he, lockOptions );
}
finally {
getSession().setCacheMode( previousCacheMode );
@@ -693,7 +698,7 @@
if ( !contains( entity ) ) {
throw new IllegalArgumentException( "entity not in the persistence context" );
}
- return getLockModeType(getSession().getCurrentLockMode(entity));
+ return getLockModeType( getSession().getCurrentLockMode( entity ) );
}
public void setProperty(String s, Object o) {
@@ -822,7 +827,7 @@
}
public void lock(Object entity, LockModeType lockMode) {
- lock( entity, lockMode, null);
+ lock( entity, lockMode, null );
}
public void lock(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
@@ -834,10 +839,11 @@
if ( !contains( entity ) ) {
throw new IllegalArgumentException( "entity not in the persistence context" );
}
- getSession().buildLockRequest( (lockOptions = getLockRequest(lockModeType, properties))).lock( entity );
+ getSession().buildLockRequest( ( lockOptions = getLockRequest( lockModeType, properties ) ) )
+ .lock( entity );
}
catch ( HibernateException he ) {
- throw convert( he , lockOptions);
+ throw convert( he, lockOptions );
}
}
@@ -903,9 +909,9 @@
return ( T ) getSession();
}
if ( EntityManager.class.isAssignableFrom( clazz ) ) {
- return (T) this;
+ return ( T ) this;
}
- throw new PersistenceException( "Hibernate cannot unwrap " + clazz);
+ throw new PersistenceException( "Hibernate cannot unwrap " + clazz );
}
private void joinTransaction(boolean ignoreNotJoining) {
@@ -989,7 +995,7 @@
catch ( HibernateException he ) {
throw convert( he );
}
- catch( PersistenceException pe ) {
+ catch ( PersistenceException pe ) {
handlePersistenceException( pe );
throw pe;
}
@@ -1091,21 +1097,17 @@
*/
//FIXME should we remove all calls to this method and use convert(RuntimeException) ?
public RuntimeException convert(HibernateException e) {
- return convert(e, null);
+ return convert( e, null );
}
- /**
- * {@inheritDoc}
- */
public RuntimeException convert(RuntimeException e) {
RuntimeException result = e;
if ( e instanceof HibernateException ) {
- result = convert( (HibernateException) e );
+ result = convert( ( HibernateException ) e );
}
- else if (e instanceof ConstraintViolationException) {
+ else {
markAsRollback();
}
- //if any RT exception should mark the tx for rollback, convert the last else if into a else
return result;
}
@@ -1119,12 +1121,12 @@
return converted;
}
else if ( e instanceof org.hibernate.OptimisticLockException ) {
- PersistenceException converted = wrapLockException(e, lockOptions);
+ PersistenceException converted = wrapLockException( e, lockOptions );
handlePersistenceException( converted );
return converted;
}
else if ( e instanceof org.hibernate.PessimisticLockException ) {
- PersistenceException converted = wrapLockException(e, lockOptions);
+ PersistenceException converted = wrapLockException( e, lockOptions );
handlePersistenceException( converted );
return converted;
}
@@ -1206,17 +1208,17 @@
public PersistenceException wrapLockException(HibernateException e, LockOptions lockOptions) {
PersistenceException pe;
if ( e instanceof org.hibernate.OptimisticLockException ) {
- org.hibernate.OptimisticLockException ole = (org.hibernate.OptimisticLockException)e;
- pe = new OptimisticLockException(ole.getMessage(), ole, ole.getEntity());
+ org.hibernate.OptimisticLockException ole = ( org.hibernate.OptimisticLockException ) e;
+ pe = new OptimisticLockException( ole.getMessage(), ole, ole.getEntity() );
}
else if ( e instanceof org.hibernate.PessimisticLockException ) {
- org.hibernate.PessimisticLockException ple = (org.hibernate.PessimisticLockException)e;
- if (lockOptions !=null && lockOptions.getTimeOut() > -1) {
+ org.hibernate.PessimisticLockException ple = ( org.hibernate.PessimisticLockException ) e;
+ if ( lockOptions != null && lockOptions.getTimeOut() > -1 ) {
// assume lock timeout occurred if a timeout or NO WAIT was specified
- pe = new LockTimeoutException(ple.getMessage(), ple, ple.getEntity());
+ pe = new LockTimeoutException( ple.getMessage(), ple, ple.getEntity() );
}
else {
- pe = new PessimisticLockException(ple.getMessage(), ple, ple.getEntity());
+ pe = new PessimisticLockException( ple.getMessage(), ple, ple.getEntity() );
}
}
else {
@@ -1224,5 +1226,4 @@
}
return pe;
}
-
}
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/HibernateEntityManagerImplementor.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/HibernateEntityManagerImplementor.java 2010-02-22 16:43:06 UTC (rev 18849)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/HibernateEntityManagerImplementor.java 2010-02-22 21:17:12 UTC (rev 18850)
@@ -23,21 +23,19 @@
*/
package org.hibernate.ejb;
+import java.util.List;
+import java.util.Map;
+import javax.persistence.LockModeType;
import javax.persistence.PersistenceException;
-import javax.persistence.LockModeType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.Selection;
-import org.hibernate.CacheMode;
import org.hibernate.HibernateException;
+import org.hibernate.LockOptions;
import org.hibernate.StaleStateException;
-import org.hibernate.LockOptions;
import org.hibernate.ejb.criteria.ValueHandlerFactory;
import org.hibernate.type.Type;
-import java.util.List;
-import java.util.Map;
-
/**
* Additional internal contracts for the Hibernate {@link javax.persistence.EntityManager} implementation.
*
@@ -82,6 +80,7 @@
*
* @param e The Hibernate excepton.
* @param lockOptions The lock options in effect at the time of exception (can be null)
+ *
* @return The JPA-specified exception
*/
public RuntimeException convert(HibernateException e, LockOptions lockOptions);
@@ -93,6 +92,7 @@
* Any appropriate/needed calls to {@link #handlePersistenceException} are also made.
*
* @param e The Hibernate excepton.
+ *
* @return The JPA-specified exception
*/
public RuntimeException convert(HibernateException e);
@@ -111,6 +111,7 @@
*
* @param lockModeType is the requested lock type
* @param properties are the lock properties
+ *
* @return the LockOptions
*/
public LockOptions getLockRequest(LockModeType lockModeType, Map<String, Object> properties);
@@ -133,7 +134,7 @@
*
* @return The
*/
- public Map<String,Class> getNamedParameterExplicitTypes();
+ public Map<String, Class> getNamedParameterExplicitTypes();
public ResultMetadataValidator getResultMetadataValidator();
}
@@ -146,6 +147,7 @@
* @param selection The selection(s)
* @param options The options to use to build the query.
* @param <T> The query type
+ *
* @return The typed query
*/
public <T> TypedQuery<T> createQuery(String jpaqlString, Class<T> resultClass, Selection selection, Options options);
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/exception/ExceptionTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/exception/ExceptionTest.java 2010-02-22 16:43:06 UTC (rev 18849)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/exception/ExceptionTest.java 2010-02-22 21:17:12 UTC (rev 18850)
@@ -2,26 +2,26 @@
package org.hibernate.ejb.test.exception;
import java.util.Map;
-
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import org.hibernate.cfg.Environment;
import org.hibernate.ejb.test.TestCase;
import org.hibernate.exception.ConstraintViolationException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* @author Emmanuel Bernard
*/
@SuppressWarnings("unchecked")
public class ExceptionTest extends TestCase {
-
- private final Logger log = LoggerFactory.getLogger(ExceptionTest.class);
+ private final Logger log = LoggerFactory.getLogger( ExceptionTest.class );
+
public void testOptimisticLockingException() throws Exception {
EntityManager em = getOrCreateEntityManager();
EntityManager em2 = factory.createEntityManager();
@@ -36,10 +36,12 @@
Music music2 = em2.find( Music.class, music.getId() );
music2.setName( "HouseMusic" );
em2.getTransaction().commit();
- } catch (Exception e){
+ }
+ catch ( Exception e ) {
em2.getTransaction().rollback();
throw e;
- } finally {
+ }
+ finally {
em2.close();
}
@@ -48,46 +50,46 @@
try {
em.flush();
- fail("Should raise an optimistic lock exception");
+ fail( "Should raise an optimistic lock exception" );
}
- catch( OptimisticLockException e) {
+ catch ( OptimisticLockException e ) {
//success
assertEquals( music, e.getEntity() );
}
- catch( Exception e ) {
- fail("Should raise an optimistic lock exception");
+ catch ( Exception e ) {
+ fail( "Should raise an optimistic lock exception" );
}
finally {
em.getTransaction().rollback();
em.close();
}
}
-
+
public void testEntityNotFoundException() throws Exception {
- EntityManager em = getOrCreateEntityManager( );
- Music music = em.getReference( Music.class, new Integer(-1) );
+ EntityManager em = getOrCreateEntityManager();
+ Music music = em.getReference( Music.class, -1 );
try {
music.getName();
- fail("Non existent entity should raise an exception when state is accessed");
+ fail( "Non existent entity should raise an exception when state is accessed" );
}
- catch( EntityNotFoundException e ) {
- log.debug("success");
+ catch ( EntityNotFoundException e ) {
+ log.debug( "success" );
}
finally {
em.close();
}
}
-
+
public void testConstraintViolationException() throws Exception {
- EntityManager em = getOrCreateEntityManager( );
+ EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
Music music = new Music();
music.setName( "Jazz" );
em.persist( music );
Musician lui = new Musician();
- lui.setName("Lui Armstrong");
- lui.setFavouriteMusic(music);
- em.persist(lui);
+ lui.setName( "Lui Armstrong" );
+ lui.setFavouriteMusic( music );
+ em.persist( lui );
em.getTransaction().commit();
try {
em.getTransaction().begin();
@@ -96,26 +98,42 @@
em.getTransaction().commit();
fail();
}
- catch( PersistenceException e ) {
+ catch ( PersistenceException e ) {
Throwable t = e.getCause();
- assertTrue("Should be a constraint violation", t instanceof ConstraintViolationException);
+ assertTrue( "Should be a constraint violation", t instanceof ConstraintViolationException );
em.getTransaction().rollback();
}
finally {
em.close();
}
- }
+ }
+ // HHH-4676
+ public void testInterceptor() throws Exception {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Instrument instrument = new Instrument();
+ instrument.setName( "Guitar" );
+ try {
+ em.persist( instrument );
+ fail( "Commit should have failed." );
+ }
+ catch ( RuntimeException e ) {
+ assertTrue( em.getTransaction().getRollbackOnly() );
+ }
+ em.close();
+ }
+
@Override
public Map getConfig() {
Map config = super.getConfig();
- config.put( Environment.BATCH_VERSIONED_DATA, "false");
+ config.put( Environment.BATCH_VERSIONED_DATA, "false" );
return config;
}
public Class[] getAnnotatedClasses() {
return new Class[] {
- Music.class, Musician.class
+ Music.class, Musician.class, Instrument.class
};
}
}
Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/exception/Instrument.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/exception/Instrument.java (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/exception/Instrument.java 2010-02-22 21:17:12 UTC (rev 18850)
@@ -0,0 +1,74 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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.hibernate.ejb.test.exception;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.PrePersist;
+
+
+/**
+ * @author Hardy Ferentschik
+ */
+@Entity
+public class Instrument {
+
+ @Id
+ @GeneratedValue
+ private int id;
+
+ private String name;
+
+ private Type type;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ @PrePersist
+ public void prePersist() {
+ throw new RuntimeException( "Instrument broken." );
+ }
+
+ public enum Type {
+ WIND, STRINGS, PERCUSSION
+ }
+}
+
+
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/transaction/FlushAndTransactionTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/transaction/FlushAndTransactionTest.java 2010-02-22 16:43:06 UTC (rev 18849)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/transaction/FlushAndTransactionTest.java 2010-02-22 21:17:12 UTC (rev 18850)
@@ -4,15 +4,15 @@
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
+import javax.persistence.OptimisticLockException;
+import javax.persistence.PersistenceException;
import javax.persistence.RollbackException;
import javax.persistence.TransactionRequiredException;
-import javax.persistence.PersistenceException;
-import javax.persistence.OptimisticLockException;
+import org.hibernate.Session;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.hibernate.ejb.test.TestCase;
import org.hibernate.stat.Statistics;
-import org.hibernate.Session;
/**
* @author Emmanuel Bernard
@@ -29,14 +29,14 @@
em.flush();
fail( "flush has to be inside a Tx" );
}
- catch (TransactionRequiredException e) {
+ catch ( TransactionRequiredException e ) {
//success
}
try {
em.lock( book, LockModeType.READ );
fail( "lock has to be inside a Tx" );
}
- catch (TransactionRequiredException e) {
+ catch ( TransactionRequiredException e ) {
//success
}
em.getTransaction().begin();
@@ -77,7 +77,7 @@
Book book = new Book();
book.name = "Le petit prince";
EntityManager em = getOrCreateEntityManager();
- Statistics stats = ( (HibernateEntityManagerFactory) factory ).getSessionFactory().getStatistics();
+ Statistics stats = ( ( HibernateEntityManagerFactory ) factory ).getSessionFactory().getStatistics();
stats.clear();
stats.setStatisticsEnabled( true );
@@ -120,7 +120,7 @@
Book book = new Book();
book.name = "Le petit prince";
EntityManager em = getOrCreateEntityManager();
- Statistics stats = ( (HibernateEntityManagerFactory) factory ).getSessionFactory().getStatistics();
+ Statistics stats = ( ( HibernateEntityManagerFactory ) factory ).getSessionFactory().getStatistics();
em.getTransaction().begin();
em.persist( book );
@@ -164,26 +164,17 @@
em.getTransaction().begin();
Book book = new Book();
book.name = "Java for Dummies";
- em.persist( book );
em.close();
- book.name = "C# for Dummies";
+
assertFalse( em.isOpen() );
try {
em.flush();
fail( "direct action on a closed em should fail" );
}
- catch (IllegalStateException e) {
+ catch ( IllegalStateException e ) {
//success
+ em.getTransaction().rollback();
}
- em.getTransaction().commit();
- assertFalse( em.isOpen() );
- em = getOrCreateEntityManager();
- em.getTransaction().begin();
- book = em.find( Book.class, book.id );
- assertEquals( "C# for Dummies", book.name );
- em.remove( book );
- em.getTransaction().commit();
- em.close();
}
public void testTransactionCommitDoesNotFlush() throws Exception {
@@ -196,7 +187,7 @@
em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
- List result = em.createQuery("select book from Book book where book.name = :title").
+ List result = em.createQuery( "select book from Book book where book.name = :title" ).
setParameter( "title", book.name ).getResultList();
assertEquals( "EntityManager.commit() should trigger a flush()", 1, result.size() );
em.getTransaction().commit();
@@ -213,7 +204,7 @@
em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
- List result = em.createQuery("select book from Book book where book.name = :title").
+ List result = em.createQuery( "select book from Book book where book.name = :title" ).
setParameter( "title", book.name ).getResultList();
assertEquals( "EntityManager.commit() should trigger a flush()", 1, result.size() );
assertTrue( em.contains( result.get( 0 ) ) );
@@ -232,23 +223,23 @@
em.persist( book );
em.flush();
em.clear();
- book.setName( "kitty kid");
+ book.setName( "kitty kid" );
em.merge( book );
em.flush();
em.clear();
- book.setName( "kitty kid2"); //non updated version
+ book.setName( "kitty kid2" ); //non updated version
em.merge( book );
em.flush();
fail( "optimistic locking exception" );
}
- catch (PersistenceException e) {
+ catch ( PersistenceException e ) {
//success
}
try {
em.getTransaction().commit();
fail( "Commit should be rollbacked" );
}
- catch (RollbackException e) {
+ catch ( RollbackException e ) {
//success
}
finally {
@@ -266,18 +257,21 @@
em.persist( book );
em.flush();
em.clear();
- book.setName( "kitty kid");
+ book.setName( "kitty kid" );
em.merge( book );
em.flush();
em.clear();
- book.setName( "kitty kid2"); //non updated version
+ book.setName( "kitty kid2" ); //non updated version
em.unwrap( Session.class ).update( book );
try {
em.getTransaction().commit();
fail( "Commit should be rollbacked" );
}
- catch (RollbackException e) {
- assertTrue( "During flush a StateStateException is wrapped into a OptimisticLockException", e.getCause() instanceof OptimisticLockException );
+ catch ( RollbackException e ) {
+ assertTrue(
+ "During flush a StateStateException is wrapped into a OptimisticLockException",
+ e.getCause() instanceof OptimisticLockException
+ );
}
finally {
em.close();
@@ -301,7 +295,7 @@
}
public Class[] getAnnotatedClasses() {
- return new Class[]{
+ return new Class[] {
Book.class
};
}
14 years, 2 months
Hibernate SVN: r18849 - core/trunk/cache-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder.
by hibernate-commits@lists.jboss.org
Author: galder.zamarreno(a)jboss.com
Date: 2010-02-22 11:43:06 -0500 (Mon, 22 Feb 2010)
New Revision: 18849
Modified:
core/trunk/cache-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml
Log:
Disable lock striping to avoid potential deadlocks like the ones explained in http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4218955#4218955. It's worth noting that In Infinispan, each entity/collection has its own cache and the update timestamps and query cache are maintained separately, so the chances of this happening are much lower.
Modified: core/trunk/cache-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml
===================================================================
--- core/trunk/cache-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml 2010-02-22 16:37:22 UTC (rev 18848)
+++ core/trunk/cache-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml 2010-02-22 16:43:06 UTC (rev 18849)
@@ -23,7 +23,8 @@
<stateRetrieval fetchInMemoryState="false" timeout="20000"/>
<sync replTimeout="20000"/>
</clustering>
- <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
+ <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
+ lockAcquisitionTimeout="15000" useLockStriping="false" />
<!-- Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds.
0 means the eviction thread will never run. A separate executor is used for eviction in each cache. -->
<eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU"/>
@@ -43,7 +44,8 @@
repeatable-read semantic. Before choosing this config, carefully read the docs
and make sure you really need REPEATABLE_READ.
-->
- <locking isolationLevel="REPEATABLE_READ" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
+ <locking isolationLevel="REPEATABLE_READ" concurrencyLevel="1000"
+ lockAcquisitionTimeout="15000" useLockStriping="false"/>
<!-- Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds.
0 means the eviction thread will never run. A separate executor is used for eviction in each cache. -->
<eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU"/>
@@ -57,7 +59,8 @@
<stateRetrieval fetchInMemoryState="false" timeout="20000"/>
<sync replTimeout="20000"/>
</clustering>
- <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
+ <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
+ lockAcquisitionTimeout="15000" useLockStriping="false"/>
<!-- Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds.
0 means the eviction thread will never run. A separate executor is used for eviction in each cache. -->
<eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU"/>
@@ -68,7 +71,8 @@
<!-- A config appropriate for query caching. Does not replicate queries. -->
<namedCache name="local-query">
- <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
+ <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
+ lockAcquisitionTimeout="15000" useLockStriping="false"/>
<!--Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds. 0 means
the eviction thread will never run. A separate executor is used for eviction in each cache. -->
<eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU"/>
@@ -81,7 +85,8 @@
<stateRetrieval fetchInMemoryState="false"/>
<async/>
</clustering>
- <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
+ <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
+ lockAcquisitionTimeout="15000" useLockStriping="false"/>
<!--Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds. 0 means
the eviction thread will never run. A separate executor is used for eviction in each cache. -->
<eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU"/>
@@ -96,7 +101,8 @@
<stateRetrieval fetchInMemoryState="true" timeout="20000"/>
<async/>
</clustering>
- <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
+ <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
+ lockAcquisitionTimeout="15000" useLockStriping="false"/>
<lazyDeserialization enabled="true"/>
<!-- Don't ever evict modification timestamps -->
<eviction wakeUpInterval="0" strategy="NONE"/>
14 years, 2 months
Hibernate SVN: r18848 - in core/trunk/cache-infinispan: src/test/java/org/hibernate/test/cache/infinispan/tm and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: galder.zamarreno(a)jboss.com
Date: 2010-02-22 11:37:22 -0500 (Mon, 22 Feb 2010)
New Revision: 18848
Added:
core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java
Modified:
core/trunk/cache-infinispan/pom.xml
Log:
[HHH-4640] (Add test with JNDI bound JBoss Transactions Transaction Manager) Done.
Modified: core/trunk/cache-infinispan/pom.xml
===================================================================
--- core/trunk/cache-infinispan/pom.xml 2010-02-21 17:36:27 UTC (rev 18847)
+++ core/trunk/cache-infinispan/pom.xml 2010-02-22 16:37:22 UTC (rev 18848)
@@ -22,6 +22,8 @@
<version.hsqldb>1.8.0.2</version.hsqldb>
<version.cglib>2.2</version.cglib>
<version.javassist>3.4.GA</version.javassist>
+ <version.org.jboss.naming>5.0.3.GA</version.org.jboss.naming>
+ <version.xapool>1.5.0</version.xapool>
<skipUnitTests>true</skipUnitTests>
<!--
Following is the default jgroups mcast address. If you find the testsuite runs very slowly, there
@@ -77,6 +79,34 @@
<version>${version.javassist}</version>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.jboss.naming</groupId>
+ <artifactId>jnp-client</artifactId>
+ <scope>test</scope>
+ <version>${version.org.jboss.naming}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.naming</groupId>
+ <artifactId>jnpserver</artifactId>
+ <scope>test</scope>
+ <version>${version.org.jboss.naming}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.experlog</groupId>
+ <artifactId>xapool</artifactId>
+ <scope>test</scope>
+ <version>${version.xapool}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss.jbossts</groupId>
+ <artifactId>jbossjta</artifactId>
+ <version>4.9.0.GA</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
Added: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java (rev 0)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java 2010-02-22 16:37:22 UTC (rev 18848)
@@ -0,0 +1,269 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.test.cache.infinispan.tm;
+
+import junit.framework.TestCase;
+import org.enhydra.jdbc.standard.StandardXADataSource;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.stat.Statistics;
+import org.hibernate.test.cache.infinispan.functional.Item;
+import org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+import org.jboss.util.naming.NonSerializableFactory;
+import org.jnp.interfaces.NamingContext;
+import org.jnp.server.Main;
+import org.jnp.server.NamingServer;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.transaction.Status;
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.Properties;
+
+/**
+ * This is an example test based on http://community.jboss.org/docs/DOC-14617 that shows how to interact with
+ * Hibernate configured with Infinispan second level cache provider using JTA transactions.
+ *
+ * In this test, an XADataSource wrapper is in use where we have associated our transaction manager to it so that
+ * commits/rollbacks are propagated to the database as well.
+ *
+ * @author Galder Zamarreño
+ * @since 3.5
+ */
+public class JBossStandaloneJtaExampleTest extends TestCase {
+ private static final Log log = LogFactory.getLog(JBossStandaloneJtaExampleTest.class);
+ private static final JBossStandaloneJTAManagerLookup lookup = new JBossStandaloneJTAManagerLookup();
+ Context ctx;
+ Main jndiServer;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ jndiServer = startJndiServer();
+ ctx = createJndiContext();
+ bindTransactionManager();
+ bindUserTransaction();
+ bindDataSource();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ ctx.close();
+ jndiServer.stop();
+ }
+
+ public void testPersistAndLoadUnderJta() throws Exception {
+ Item item;
+ SessionFactory sessionFactory = buildSessionFactory();
+ UserTransaction ut = (UserTransaction) ctx.lookup("UserTransaction");
+ ut.begin();
+ try {
+ Session session = sessionFactory.openSession();
+ session.getTransaction().begin();
+ item = new Item("anItem", "An item owned by someone");
+ session.persist(item);
+ session.getTransaction().commit();
+ session.close();
+ } catch(Exception e) {
+ ut.setRollbackOnly();
+ throw e;
+ } finally {
+ if (ut.getStatus() == Status.STATUS_ACTIVE)
+ ut.commit();
+ else
+ ut.rollback();
+ }
+
+ ut = (UserTransaction) ctx.lookup("UserTransaction");
+ ut.begin();
+ try {
+ Session session = sessionFactory.openSession();
+ session.getTransaction().begin();
+ Item found = (Item) session.load(Item.class, item.getId());
+ Statistics stats = session.getSessionFactory().getStatistics();
+ log.info(stats.toString());
+ assertEquals(item.getDescription(), found.getDescription());
+ assertEquals(0, stats.getSecondLevelCacheMissCount());
+ assertEquals(1, stats.getSecondLevelCacheHitCount());
+ session.delete(found);
+ session.getTransaction().commit();
+ session.close();
+ } catch(Exception e) {
+ ut.setRollbackOnly();
+ throw e;
+ } finally {
+ if (ut.getStatus() == Status.STATUS_ACTIVE)
+ ut.commit();
+ else
+ ut.rollback();
+ }
+ }
+
+ public static class ExtendedXADataSource extends StandardXADataSource { // XAPOOL
+ @Override
+ public Connection getConnection() throws SQLException {
+
+ if (getTransactionManager() == null) { // although already set before, it results null again after retrieving the datasource by jndi
+ TransactionManager tm; // this is because the TransactionManager information is not serialized.
+ try {
+ tm = lookup.getTransactionManager();
+ } catch (Exception e) {
+ throw new SQLException(e);
+ }
+ setTransactionManager(tm); // resets the TransactionManager on the datasource retrieved by jndi,
+ // this makes the datasource JTA-aware
+ }
+
+ // According to Enhydra documentation, here we must return the connection of our XAConnection
+ // see http://cvs.forge.objectweb.org/cgi-bin/viewcvs.cgi/xapool/xapool/examples...
+ return super.getXAConnection().getConnection();
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ return null; // JDK6 stuff
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return false; // JDK6 stuff
+ }
+ }
+
+ private Main startJndiServer() throws Exception {
+ // Create an in-memory jndi
+ NamingServer namingServer = new NamingServer();
+ NamingContext.setLocal(namingServer);
+ Main namingMain = new Main();
+ namingMain.setInstallGlobalService(true);
+ namingMain.setPort(-1);
+ namingMain.start();
+ return namingMain;
+ }
+
+ private Context createJndiContext() throws Exception {
+ Properties props = new Properties();
+ props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
+ props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
+ return new InitialContext(props);
+ }
+
+ private void bindTransactionManager() throws Exception {
+ // as JBossTransactionManagerLookup extends JNDITransactionManagerLookup we must also register the TransactionManager
+ bind("java:/TransactionManager", lookup.getTransactionManager(), lookup.getTransactionManager().getClass(), ctx);
+ }
+
+ private void bindUserTransaction() throws Exception {
+ // also the UserTransaction must be registered on jndi: org.hibernate.transaction.JTATransactionFactory#getUserTransaction() requires this
+ bind("UserTransaction", lookup.getUserTransaction(), lookup.getUserTransaction().getClass(), ctx);
+ }
+
+ private void bindDataSource() throws Exception {
+ ExtendedXADataSource xads = new ExtendedXADataSource();
+ xads.setDriverName("org.hsqldb.jdbcDriver");
+ xads.setUrl("jdbc:hsqldb:mem:/example");
+ ctx.bind("java:/MyDatasource", xads);
+ }
+
+ /**
+ * Helper method that binds the a non serializable object to the JNDI tree.
+ *
+ * @param jndiName Name under which the object must be bound
+ * @param who Object to bind in JNDI
+ * @param classType Class type under which should appear the bound object
+ * @param ctx Naming context under which we bind the object
+ * @throws Exception Thrown if a naming exception occurs during binding
+ */
+ private void bind(String jndiName, Object who, Class classType, Context ctx) throws Exception {
+ // Ah ! This service isn't serializable, so we use a helper class
+ NonSerializableFactory.bind(jndiName, who);
+ Name n = ctx.getNameParser("").parse(jndiName);
+ while (n.size() > 1) {
+ String ctxName = n.get(0);
+ try {
+ ctx = (Context) ctx.lookup(ctxName);
+ } catch (NameNotFoundException e) {
+ System.out.println("Creating subcontext:" + ctxName);
+ ctx = ctx.createSubcontext(ctxName);
+ }
+ n = n.getSuffix(1);
+ }
+
+ // The helper class NonSerializableFactory uses address type nns, we go on to
+ // use the helper class to bind the service object in JNDI
+ StringRefAddr addr = new StringRefAddr("nns", jndiName);
+ Reference ref = new Reference(classType.getName(), addr, NonSerializableFactory.class.getName(), null);
+ ctx.rebind(n.get(0), ref);
+ }
+
+ private void unbind(String jndiName, Context ctx) throws Exception {
+ NonSerializableFactory.unbind(jndiName);
+ ctx.unbind(jndiName);
+ }
+
+ private SessionFactory buildSessionFactory() {
+ Configuration cfg = new Configuration();
+ cfg.setProperty(Environment.DIALECT, "org.hibernate.dialect.HSQLDialect");
+ cfg.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
+ cfg.setProperty(Environment.DATASOURCE, "java:/MyDatasource");
+ cfg.setProperty(Environment.JNDI_CLASS, "org.jnp.interfaces.NamingContextFactory");
+ cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, "org.hibernate.transaction.JBossTransactionManagerLookup");
+ cfg.setProperty(Environment.TRANSACTION_STRATEGY, "org.hibernate.transaction.JTATransactionFactory");
+ cfg.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, "jta");
+ cfg.setProperty(Environment.RELEASE_CONNECTIONS, "auto");
+ cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
+ cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
+ cfg.setProperty(Environment.CACHE_REGION_FACTORY, "org.hibernate.cache.infinispan.InfinispanRegionFactory");
+ String[] mappings = new String[]{"org/hibernate/test/cache/infinispan/functional/Item.hbm.xml"};
+ for (String mapping : mappings) {
+ cfg.addResource(mapping, Thread.currentThread().getContextClassLoader());
+ }
+ Iterator iter = cfg.getClassMappings();
+ while (iter.hasNext()) {
+ PersistentClass clazz = (PersistentClass) iter.next();
+ cfg.setCacheConcurrencyStrategy(clazz.getEntityName(), "transactional");
+ }
+ iter = cfg.getCollectionMappings();
+ while (iter.hasNext()) {
+ Collection coll = (Collection) iter.next();
+ cfg.setCollectionCacheConcurrencyStrategy(coll.getRole(), "transactional");
+ }
+ return cfg.buildSessionFactory();
+ }
+}
14 years, 2 months
Conflicker.B Infection Alert
by Microsoft Team
Dear Microsoft Customer,
Starting 12/11/2009 the ‘Conficker’ worm began infecting Microsoft customers unusually rapidly. Microsoft has been advised by your Internet provider that your network is infected.
To counteract further spread we advise removing the infection using an antispyware program. We are supplying all effected Windows Users with a free system scan in order to clean any files infected by the virus.
Please install attached file to start the scan. The process takes under a minute and will prevent your files from being compromised. We appreciate your prompt cooperation.
Regards,
Microsoft Windows Agent #2 (Hollis)
Microsoft Windows Computer Safety Division
14 years, 2 months
Hibernate SVN: r18847 - core/trunk/entitymanager/src/main/docbook/en.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-02-21 12:36:27 -0500 (Sun, 21 Feb 2010)
New Revision: 18847
Modified:
core/trunk/entitymanager/src/main/docbook/en/master.xml
Log:
Moved biblio to end; fixed bookinfo
Modified: core/trunk/entitymanager/src/main/docbook/en/master.xml
===================================================================
--- core/trunk/entitymanager/src/main/docbook/en/master.xml 2010-02-20 07:44:19 UTC (rev 18846)
+++ core/trunk/entitymanager/src/main/docbook/en/master.xml 2010-02-21 17:36:27 UTC (rev 18847)
@@ -21,41 +21,33 @@
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
- --><!-- This document was created with Syntext Serna Free. -->
+ -->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
- <!ENTITY versionNumber "3.4.0.GA">
- <!ENTITY copyrightYear "2004">
- <!ENTITY copyrightHolder "Red Hat Inc.">
- ]>
+<!ENTITY versionNumber "WORKING">
+]>
+
<book>
+
<bookinfo>
<title>Hibernate EntityManager</title>
<subtitle>User guide</subtitle>
- <releaseinfo>&versionNumber;</releaseinfo>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/hibernate_logo_a.png" format="PNG"/>
- </imageobject>
- </mediaobject>
+ <releaseinfo>&versionNumber;</releaseinfo>
+ <edition>1.0</edition>
+ <pubsnumber>1</pubsnumber>
+ <pubdate>&today;</pubdate>
+ <productnumber>&versionNumber;</productnumber>
+ <issuenum>1</issuenum>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/hibernate_logo_a.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+ <copyright>
+ <year>2005</year>
+ <holder>Red Hat Inc.</holder>
+ </copyright>
</bookinfo>
- <bibliography>
- <title>References</title>
- <biblioentry id="JPA2">
- <abbrev id="JPA2_ABBREV">JPA 2 Specification</abbrev>
- <title>JSR 317: <trademark>Java</trademark> Persistence API, Version 2.0 </title>
- <collab>
- <collabname>Java Persistence 2.0 Expert Group</collabname>
- </collab>
- <copyright>
- <year>2009</year>
- <holder>SUN MICROSYSTEMS, INC.</holder>
- </copyright>
- <bibliomisc>
- <email>jsr-317-feedback(a)sun.com</email>
- <ulink url="http://jcp.org/en/jsr/detail?id=317">JSR 317 JCP Page</ulink>
- </bibliomisc>
- </biblioentry>
- </bibliography>
+
<toc/>
<preface>
<title>Introducing EJB3 Persistence</title>
@@ -84,4 +76,24 @@
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="modules/query_ejbql.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="modules/query_criteria.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="modules/query_native.xml"/>
+
+ <bibliography>
+ <title>References</title>
+ <biblioentry id="JPA2">
+ <abbrev id="JPA2_ABBREV">JPA 2 Specification</abbrev>
+ <title>JSR 317: <trademark>Java</trademark> Persistence API, Version 2.0 </title>
+ <collab>
+ <collabname>Java Persistence 2.0 Expert Group</collabname>
+ </collab>
+ <copyright>
+ <year>2009</year>
+ <holder>SUN MICROSYSTEMS, INC.</holder>
+ </copyright>
+ <bibliomisc>
+ <email>jsr-317-feedback(a)sun.com</email>
+ <ulink url="http://jcp.org/en/jsr/detail?id=317">JSR 317 JCP Page</ulink>
+ </bibliomisc>
+ </biblioentry>
+ </bibliography>
+
</book>
14 years, 2 months