mirror of https://github.com/apache/openjpa.git
OPENJPA-2099: Align Slice threading model and Select reuse threading model
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1235594 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
49adef7c61
commit
816280b17b
|
@ -83,13 +83,14 @@ import org.apache.openjpa.util.UserException;
|
|||
* @author Abe White
|
||||
* @nojavadoc
|
||||
*/
|
||||
@SuppressWarnings({ "serial", "deprecation" })
|
||||
public class JDBCStoreQuery
|
||||
extends ExpressionStoreQuery {
|
||||
|
||||
private static final Table INVALID = new Table();
|
||||
|
||||
// add all standard filter and aggregate listeners to these maps
|
||||
private static final Map _listeners = new HashMap();
|
||||
private static final Map<String,FilterListener> _listeners = new HashMap<String, FilterListener>();
|
||||
|
||||
static {
|
||||
// deprecated extensions
|
||||
|
@ -186,8 +187,8 @@ public class JDBCStoreQuery
|
|||
ExpContext ctx = new ExpContext(_store, params, fetch);
|
||||
|
||||
// add selects with populate WHERE conditions to list
|
||||
List sels = new ArrayList(mappings.length);
|
||||
List selMappings = new ArrayList(mappings.length);
|
||||
List<Select> sels = new ArrayList<Select>(mappings.length);
|
||||
List<ClassMapping> selMappings = new ArrayList<ClassMapping>(mappings.length);
|
||||
BitSet subclassBits = new BitSet();
|
||||
BitSet nextBits = new BitSet();
|
||||
boolean unionable = createWhereSelects(sels, mappings, selMappings,
|
||||
|
@ -335,8 +336,8 @@ public class JDBCStoreQuery
|
|||
* Generate the selects with WHERE conditions needed to execute the query
|
||||
* for the given mappings.
|
||||
*/
|
||||
private boolean createWhereSelects(List sels, ClassMapping[] mappings,
|
||||
List selMappings, boolean subclasses, BitSet subclassBits,
|
||||
private boolean createWhereSelects(List<Select> sels, ClassMapping[] mappings,
|
||||
List<ClassMapping> selMappings, boolean subclasses, BitSet subclassBits,
|
||||
BitSet nextBits, ExpressionFactory[] facts, QueryExpressions[] exps,
|
||||
QueryExpressionsState[] states, ExpContext ctx, int subclassMode) {
|
||||
Number optHint = (Number) ctx.fetch.getHint
|
||||
|
@ -364,12 +365,12 @@ public class JDBCStoreQuery
|
|||
else if (this.ctx.isUnique())
|
||||
sel.setExpectedResultCount(1, false);
|
||||
|
||||
List selectFrom = getJoinedTableMeta(sel);
|
||||
List<ClassMapping> selectFrom = getJoinedTableMeta(sel);
|
||||
int size = 0;
|
||||
if (selectFrom != null) {
|
||||
size = selectFrom.size();
|
||||
for (int j = 0; j < size; j++) {
|
||||
ClassMapping vert = (ClassMapping)selectFrom.get(j);
|
||||
ClassMapping vert = selectFrom.get(j);
|
||||
selMappings.add(vert);
|
||||
if (j == size - 1) {
|
||||
nextBits.set(sels.size());
|
||||
|
@ -388,7 +389,7 @@ public class JDBCStoreQuery
|
|||
nextBits.set(sels.size());
|
||||
sels.add(sel);
|
||||
} else
|
||||
sels.add(sel.fullClone(1));
|
||||
sels.add((Select)sel.fullClone(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,17 +401,17 @@ public class JDBCStoreQuery
|
|||
return unionable;
|
||||
}
|
||||
|
||||
private List getJoinedTableMeta(Select sel) {
|
||||
List selectFrom = sel.getJoinedTableClassMeta();
|
||||
List exSelectFrom = sel.getExcludedJoinedTableClassMeta();
|
||||
private List<ClassMapping> getJoinedTableMeta(Select sel) {
|
||||
List<ClassMapping> selectFrom = sel.getJoinedTableClassMeta();
|
||||
List<ClassMapping> exSelectFrom = sel.getExcludedJoinedTableClassMeta();
|
||||
if (exSelectFrom == null)
|
||||
return selectFrom;
|
||||
if (selectFrom == null)
|
||||
return null;
|
||||
int size = selectFrom.size();
|
||||
List retList = new ArrayList(size);
|
||||
List<ClassMapping> retList = new ArrayList<ClassMapping>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object obj = selectFrom.get(i);
|
||||
ClassMapping obj = selectFrom.get(i);
|
||||
if (!exSelectFrom.contains(obj))
|
||||
retList.add(obj);
|
||||
}
|
||||
|
@ -430,15 +431,15 @@ public class JDBCStoreQuery
|
|||
|| !hasVerticalSubclasses(mapping))
|
||||
return new ClassMapping[] { mapping };
|
||||
|
||||
List subs = new ArrayList(4);
|
||||
List<ClassMapping> subs = new ArrayList<ClassMapping>(4);
|
||||
addSubclasses(mapping, subs);
|
||||
return (ClassMapping[]) subs.toArray(new ClassMapping[subs.size()]);
|
||||
return subs.toArray(new ClassMapping[subs.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive helper to add mappings for subclasses to the given list.
|
||||
*/
|
||||
private void addSubclasses(ClassMapping mapping, Collection subs) {
|
||||
private void addSubclasses(ClassMapping mapping, Collection<ClassMapping> subs) {
|
||||
// possible future optimizations:
|
||||
// - if no fields in meta or its subclasses (and not in an
|
||||
// already-selected table) are in the current fetch
|
||||
|
@ -699,8 +700,8 @@ public class JDBCStoreQuery
|
|||
ExpContext ctx = new ExpContext(_store, params, fetch);
|
||||
|
||||
// add selects with populate WHERE conditions to list
|
||||
List sels = new ArrayList(mappings.length);
|
||||
List selMappings = new ArrayList(mappings.length);
|
||||
List<Select> sels = new ArrayList<Select>(mappings.length);
|
||||
List<ClassMapping> selMappings = new ArrayList<ClassMapping>(mappings.length);
|
||||
BitSet subclassBits = new BitSet();
|
||||
BitSet nextBits = new BitSet();
|
||||
boolean unionable = createWhereSelects(sels, mappings, selMappings,
|
||||
|
@ -797,11 +798,11 @@ public class JDBCStoreQuery
|
|||
(org.apache.openjpa.jdbc.kernel.exps.Math) value;
|
||||
Val value1 = mathVal.getVal1();
|
||||
Object val1 = getValue(value1, ob, params, sm);
|
||||
Class c1 = value1.getType();
|
||||
Class<?> c1 = value1.getType();
|
||||
|
||||
Val value2 = mathVal.getVal2();
|
||||
Object val2 = getValue(value2, ob, params, sm);
|
||||
Class c2 = value2.getType();
|
||||
Class<?> c2 = value2.getType();
|
||||
|
||||
String op = mathVal.getOperation();
|
||||
if (op.equals(org.apache.openjpa.jdbc.kernel.exps.Math.ADD))
|
||||
|
@ -942,7 +943,7 @@ public class JDBCStoreQuery
|
|||
org.apache.openjpa.jdbc.kernel.exps.Abs absVal =
|
||||
(org.apache.openjpa.jdbc.kernel.exps.Abs) value;
|
||||
Object val = getValue(absVal.getValue(), ob, params, sm);
|
||||
Class c = val.getClass();
|
||||
Class<?> c = val.getClass();
|
||||
if (c == Integer.class)
|
||||
return Integer.valueOf(java.lang.Math.abs(((Integer) val).intValue()));
|
||||
else if (c == Float.class)
|
||||
|
@ -959,7 +960,7 @@ public class JDBCStoreQuery
|
|||
org.apache.openjpa.jdbc.kernel.exps.Sqrt sqrtVal =
|
||||
(org.apache.openjpa.jdbc.kernel.exps.Sqrt) value;
|
||||
Object val = getValue(sqrtVal.getValue(), ob, params, sm);
|
||||
Class c = val.getClass();
|
||||
Class<?> c = val.getClass();
|
||||
if (c == Integer.class)
|
||||
return Double.valueOf(java.lang.Math.sqrt(((Integer) val).doubleValue()));
|
||||
else if (c == Float.class)
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
package org.apache.openjpa.jdbc.sql;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.openjpa.jdbc.schema.Column;
|
||||
|
||||
|
||||
|
@ -31,7 +34,7 @@ import org.apache.openjpa.jdbc.schema.Column;
|
|||
* select.
|
||||
* <br><b>NOTE:</b>
|
||||
* The primary assumption of usage is that the binding parameter values to a cached select and
|
||||
* executing it are carried out in the same thread.
|
||||
* executing it are carried out in the same (or <em>equivalent</em>) thread.
|
||||
* <br>
|
||||
* The parameter is further qualified by whether it is user specified (e.g. from a query parameter)
|
||||
* or internally generated (e.g. a discriminator value for inheritance join). A database column can
|
||||
|
@ -51,7 +54,7 @@ public class BindParameter {
|
|||
private final Column _column;
|
||||
// key of this parameter
|
||||
private final Object _key;
|
||||
private ThreadLocal<Object> _value = new ThreadLocal<Object>();
|
||||
private Map<Thread, Object> _value = new HashMap<Thread, Object>();
|
||||
|
||||
/**
|
||||
* Constructs a parameter with given key, column and user flag.
|
||||
|
@ -67,21 +70,34 @@ public class BindParameter {
|
|||
_key = key;
|
||||
_user = user;
|
||||
_column = column;
|
||||
_value.set(value);
|
||||
_value.put(Thread.currentThread(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value bound to this parameter. Can be null.
|
||||
* Gets the value bound to this parameter for the calling thread. Can be null.
|
||||
*
|
||||
* @exception if the current thread or its equivalent never bound a value
|
||||
* to this parameter.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return _value.get();
|
||||
Thread current = Thread.currentThread();
|
||||
if (!_value.containsKey(current)) {
|
||||
// calling thread may be a child of the thread that inserted the value.
|
||||
// This is for SliceThread
|
||||
for (Map.Entry<Thread, Object> e : _value.entrySet()) {
|
||||
if (isEquivalent(e.getKey(), current))
|
||||
return e.getValue();
|
||||
}
|
||||
throw new IllegalStateException("No value for " + current + ". Known threads " + _value.keySet());
|
||||
}
|
||||
return _value.get(current);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given value to this parameter. Can be null.
|
||||
*/
|
||||
public void setValue(Object value) {
|
||||
_value.set(value);
|
||||
_value.put(Thread.currentThread(),value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,4 +121,9 @@ public class BindParameter {
|
|||
public Object getKey() {
|
||||
return _key;
|
||||
}
|
||||
|
||||
boolean isEquivalent(Thread a, Thread b) {
|
||||
if (a == b) return true;
|
||||
return a.equals(b) || b.equals(a);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,11 +63,39 @@ import org.apache.openjpa.util.Id;
|
|||
import org.apache.openjpa.util.InternalException;
|
||||
|
||||
/**
|
||||
* Standard {@link Select} implementation. Usage note: though this class
|
||||
* implements {@link Joins}, it should not be used for joining directly.
|
||||
* Instead, use the return value of {@link #newJoins}.
|
||||
* Standard {@link Select} implementation.
|
||||
* <br>
|
||||
* This critical construct holds information to form a SQL <tt>SELECT</tt> statement.
|
||||
* The structure imitates SQL components such a {@link Selects projection terms},
|
||||
* {@link SelectImpl#_where <tt>WHERE</tt>} clause, {@link SelectImpl#_ordering
|
||||
* <tt>ORDER BY</tt>} clause, {@link SelectImpl#_subsels sub-queries} etc.
|
||||
* It also maintains tables and columns involved in the selection along with
|
||||
* their join information.
|
||||
* <br>
|
||||
* This structure is capable of holding other independent instances for fetching
|
||||
* data for related fields by either eager or parallel execution.
|
||||
* <br>
|
||||
* This instance is {@link #execute(JDBCStore, JDBCFetchConfiguration) executable}.
|
||||
* After execution, this instance becomes {@link #isReadOnly() immutable} i.e. any
|
||||
* structural modification is {@link #assertMutable() prohibited}. The only modification
|
||||
* possible is by {@link #bindParameter(SQLBuffer, Object[], Column[], PathJoins) binding}
|
||||
* different values to existing {@link BindParameter parameters}.
|
||||
* <br>
|
||||
* The {@link SelectResult result} from executing this instance of a <tt>JDBC</tt>-enabled
|
||||
* database is available for field values to be populated in in-memory persistent entities.
|
||||
* The access mechanics is critical to performance, and hence an {@link Selects#isOptimizable()
|
||||
* heuristics} is applied for optimization.
|
||||
* <br>
|
||||
* Usage note:
|
||||
* <LI>a) though this class implements {@link Joins}, it should not be used for
|
||||
* joining directly. Instead, use the return value of {@link #newJoins}.
|
||||
* <LI>b) if this instance is concurrently shared based on {@link JDBCConfiguration#getSelectCacheEnabled()
|
||||
* <tt>openjpa.jdbc.CachesSelect</tt>} setting, then the caller must ensure that the
|
||||
* parameters are bound in the same or {@link BindParameter#isEquivalent(Thread, Thread) equivalent}
|
||||
* thread in which this instance is executed.
|
||||
*
|
||||
* @author Abe White
|
||||
* @author Pinaki Poddar
|
||||
* @nojavadoc
|
||||
*/
|
||||
public class SelectImpl
|
||||
|
|
|
@ -50,6 +50,36 @@ public class SliceThread extends Thread {
|
|||
return _parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* This thread equals itself (of course), its parent and any of its siblings.
|
||||
* Essentially all slice threads are equal.
|
||||
* <br>
|
||||
* Note: this definition of equality breaks the core definition i.e. if
|
||||
* <tt>P</tt> is parent thread of a slice child <tt>S</tt>, then
|
||||
* <tt>S.equals(P)</tt>, but <em>not</em> <tt>P.equals(S)</tt>.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (other instanceof SliceThread) {
|
||||
return ((SliceThread)other)._parent == this._parent;
|
||||
}
|
||||
return this._parent == other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash code of this thread is same as its parent.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return _parent.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return '[' + getClass().getSimpleName() + '-'+ getName() + " child of " + _parent + ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cached pool of <em>slice</em> threads.
|
||||
* The thread factory creates specialized threads for preferential locking treatment.
|
||||
|
|
|
@ -356,5 +356,18 @@ public class TestBasic extends SliceTestCase {
|
|||
assertNotNull(newP);
|
||||
assertEquals("newslice", SlicePersistence.getSlice(newP));
|
||||
}
|
||||
|
||||
public void testSliceThreadEqualsParentAndSiblings() {
|
||||
Thread parent = new Thread();
|
||||
SliceThread s1 = new SliceThread(parent, null);
|
||||
SliceThread s2 = new SliceThread(parent, null);
|
||||
|
||||
assertEquals(s1, parent);
|
||||
assertEquals(s2, parent);
|
||||
assertEquals(s1, s2);
|
||||
assertNotSame(parent, s1);
|
||||
assertNotSame(parent, s2);
|
||||
assertNotSame(s1, s2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue