You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by jo...@apache.org on 2012/12/18 18:19:55 UTC
svn commit: r1423537 - in /cayenne/main/trunk: docs/doc/src/main/resources/
framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/
Author: johnthuss
Date: Tue Dec 18 17:19:55 2012
New Revision: 1423537
URL: http://svn.apache.org/viewvc?rev=1423537&view=rev
Log:
CAY-1782 Fix deadlock when performing many concurrent inserts
Removed:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/LongPkRange.java
Modified:
cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java
Modified: cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=1423537&r1=1423536&r2=1423537&view=diff
==============================================================================
--- cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt Tue Dec 18 17:19:55 2012
@@ -61,3 +61,4 @@ CAY-1755 FaultFailureException resolving
CAY-1757 ROP: Faulting entity relationship resets uncommitted modifications made to its reverse relationship
CAY-1774 EhCacheQueryCache.get(QueryMetadata, QueryCacheEntryFactory) returns null if EhCache instance for group is not present
CAY-1780 cdbimport do not create xml file in resource folder
+CAY-1782 Deadlock when performing many concurrent inserts
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java?rev=1423537&r1=1423536&r2=1423537&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java Tue Dec 18 17:19:55 2012
@@ -26,10 +26,14 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
+import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
-import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.DataRow;
@@ -52,7 +56,7 @@ public class JdbcPkGenerator implements
public static final int DEFAULT_PK_CACHE_SIZE = 20;
protected JdbcAdapter adapter;
- protected Map<String, LongPkRange> pkCache = new HashMap<String, LongPkRange>();
+ protected ConcurrentHashMap<String, SortedSet<Long>> pkCache = new ConcurrentHashMap<String, SortedSet<Long>>();
protected int pkCacheSize = DEFAULT_PK_CACHE_SIZE;
public JdbcPkGenerator(JdbcAdapter adapter) {
@@ -253,21 +257,32 @@ public class JdbcPkGenerator implements
value = longPkFromDatabase(node, entity);
}
else {
- synchronized (pkCache) {
- LongPkRange r = pkCache.get(entity.getName());
+ SortedSet<Long> pks = pkCache.get(entity.getName());
- if (r == null) {
- // created exhausted LongPkRange
- r = new LongPkRange(1l, 0l);
- pkCache.put(entity.getName(), r);
+ if (pks == null) {
+ // created exhausted LongPkRange
+ pks = new TreeSet<Long>();
+ SortedSet<Long> previousPks = pkCache.putIfAbsent(entity.getName(), pks);
+ if (previousPks != null) {
+ pks = previousPks;
}
+ }
- if (r.isExhausted()) {
- long val = longPkFromDatabase(node, entity);
- r.reset(val, val + cacheSize - 1);
- }
+ if (pks.isEmpty()) {
+ long val = longPkFromDatabase(node, entity);
+ SortedSet<Long> nextPks = mkSortedSetFromRange(val, val + cacheSize - 1);
+ while (!pkCache.replace(entity.getName(), pks, nextPks)) {
+ pks = pkCache.get(entity.getName()); // the cache for this entity has changed, so re-fetch it then update
+ SortedSet<Long> previousPlusNext = new TreeSet<Long>(pks);
+ previousPlusNext.addAll(nextPks);
+ nextPks = previousPlusNext;
+ }
+ pks = nextPks;
+ }
- value = r.getNextPrimaryKey();
+ synchronized (pkCache) {
+ value = pks.first();
+ pks.remove(value);
}
}
@@ -280,7 +295,15 @@ public class JdbcPkGenerator implements
}
}
- /**
+ private SortedSet<Long> mkSortedSetFromRange(long min, long max) {
+ SortedSet<Long> result = new TreeSet<Long>();
+ for (long i = min; i <= max; i++) {
+ result.add(i);
+ }
+ return result;
+ }
+
+ /**
* Performs primary key generation ignoring cache. Generates a range of primary keys
* as specified by "pkCacheSize" bean property.
* <p>