mirror of https://github.com/apache/openjpa.git
OPENJPA-515 Add support for targeted query via query hints
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@627888 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
caa400cbb3
commit
8a811f69ea
|
@ -50,6 +50,7 @@ public class DistributedBrokerImpl extends FinalizingBrokerImpl {
|
||||||
* operating set. The slice is assigned only if a StateManager has never
|
* operating set. The slice is assigned only if a StateManager has never
|
||||||
* been assigned before.
|
* been assigned before.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public OpenJPAStateManager persist(Object pc, Object id, boolean explicit,
|
public OpenJPAStateManager persist(Object pc, Object id, boolean explicit,
|
||||||
OpCallbacks call) {
|
OpCallbacks call) {
|
||||||
OpenJPAStateManager sm = getStateManager(pc);
|
OpenJPAStateManager sm = getStateManager(pc);
|
||||||
|
|
|
@ -38,11 +38,11 @@ public interface DistributedConfiguration extends OpenJPAConfiguration {
|
||||||
/**
|
/**
|
||||||
* Gets the active slice identifiers. This list is determined by the
|
* Gets the active slice identifiers. This list is determined by the
|
||||||
* configuration properties either by explicit listing in
|
* configuration properties either by explicit listing in
|
||||||
* <code>slice.Names</code> property or by scanning <code>slice.*.*</code>
|
* <code>openjpa.slice.Names</code> property or by scanning
|
||||||
* properties.
|
* <code>openjpa.slice.*.*</code> properties.
|
||||||
* <br>
|
* <br>
|
||||||
* The ordering of the slice identifiers is determined when they are
|
* The ordering of the slice identifiers is determined when they are
|
||||||
* specified explicitly in <code>slice.Names</code> property or
|
* specified explicitly in <code>openjpa.slice.Names</code> property or
|
||||||
* ordered alphabetically when found by scanning the properties.
|
* ordered alphabetically when found by scanning the properties.
|
||||||
* <br>
|
* <br>
|
||||||
* This list always returns the identifiers that are <em>active</em>, slices
|
* This list always returns the identifiers that are <em>active</em>, slices
|
||||||
|
@ -60,7 +60,7 @@ public interface DistributedConfiguration extends OpenJPAConfiguration {
|
||||||
/**
|
/**
|
||||||
* Gets the slices of given status.
|
* Gets the slices of given status.
|
||||||
* @param statuses list of status flags. If null, returns all slices
|
* @param statuses list of status flags. If null, returns all slices
|
||||||
* irrespective of status;
|
* irrespective of status.
|
||||||
*/
|
*/
|
||||||
List<Slice> getSlices(Slice.Status...statuses);
|
List<Slice> getSlices(Slice.Status...statuses);
|
||||||
|
|
||||||
|
|
|
@ -33,13 +33,14 @@ public interface DistributionPolicy {
|
||||||
* Gets the name of the slice where a given instance will be stored.
|
* Gets the name of the slice where a given instance will be stored.
|
||||||
*
|
*
|
||||||
* @param pc The newly persistent or to-be-merged object.
|
* @param pc The newly persistent or to-be-merged object.
|
||||||
* @param slices list of names of the configured slices. The ordering of
|
* @param slices list of names of the active slices. The ordering of
|
||||||
* the list is either explicit (by the <code>slice.Names</code> property)
|
* the list is either explicit <code>openjpa.slice.Names</code> property
|
||||||
* or implicit i.e. alphabetic if <code>slice.Names</code> is unspecified.
|
* or implicit i.e. alphabetic order of available identifiers if
|
||||||
|
* <code>openjpa.slice.Names</code> is unspecified.
|
||||||
* @param context generic persistence context managing the given instance.
|
* @param context generic persistence context managing the given instance.
|
||||||
*
|
*
|
||||||
* @return identifier of the slice. This name must match one of the
|
* @return identifier of the slice. This name must match one of the
|
||||||
* configured slice names.
|
* given slice names.
|
||||||
* @see DistributedConfiguration#getActiveSliceNames()
|
* @see DistributedConfiguration#getActiveSliceNames()
|
||||||
*/
|
*/
|
||||||
String distribute(Object pc, List<String> slices, Object context);
|
String distribute(Object pc, List<String> slices, Object context);
|
||||||
|
|
|
@ -27,13 +27,26 @@ import org.apache.openjpa.slice.jdbc.DistributedJDBCBrokerFactory;
|
||||||
/**
|
/**
|
||||||
* Derives configuration for Slice.
|
* Derives configuration for Slice.
|
||||||
* Introduces a specialized BrokerFactory aliased as <code>slice</code>.
|
* Introduces a specialized BrokerFactory aliased as <code>slice</code>.
|
||||||
* All Slice specific configuration is prefixed as <code>slice.XXX</code>
|
* All Slice specific configuration is prefixed as
|
||||||
|
* <code>openjpa.slice.*.*</code>
|
||||||
*
|
*
|
||||||
* @author Pinaki Poddar
|
* @author Pinaki Poddar
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ProductDerivation extends AbstractProductDerivation implements
|
public class ProductDerivation extends AbstractProductDerivation implements
|
||||||
OpenJPAProductDerivation {
|
OpenJPAProductDerivation {
|
||||||
|
/**
|
||||||
|
* Prefix for all Slice-specific configuration properties.
|
||||||
|
*/
|
||||||
|
public static final String PREFIX_SLICE = "openjpa.slice";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hint key <code>openjpa.hint.slice.Target </code> to specify a subset of
|
||||||
|
* slices for query. The value corresponding to the key is comma-separated
|
||||||
|
* list of slice identifiers.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static final String HINT_TARGET = "openjpa.hint.slice.Target";
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void putBrokerFactoryAliases(Map m) {
|
public void putBrokerFactoryAliases(Map m) {
|
||||||
|
@ -41,7 +54,7 @@ public class ProductDerivation extends AbstractProductDerivation implements
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getConfigurationPrefix() {
|
public String getConfigurationPrefix() {
|
||||||
return "openjpa.slice";
|
return PREFIX_SLICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getType() {
|
public int getType() {
|
||||||
|
|
|
@ -21,7 +21,8 @@ package org.apache.openjpa.slice;
|
||||||
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a database slice of immutable logical name.
|
* Represents a database slice of immutable logical name, a configuration and
|
||||||
|
* status.
|
||||||
*
|
*
|
||||||
* @author Pinaki Poddar
|
* @author Pinaki Poddar
|
||||||
*
|
*
|
||||||
|
|
|
@ -49,6 +49,7 @@ import org.apache.openjpa.lib.util.Localizer;
|
||||||
import org.apache.openjpa.slice.DistributedBrokerImpl;
|
import org.apache.openjpa.slice.DistributedBrokerImpl;
|
||||||
import org.apache.openjpa.slice.DistributionPolicy;
|
import org.apache.openjpa.slice.DistributionPolicy;
|
||||||
import org.apache.openjpa.slice.ExecutorServiceValue;
|
import org.apache.openjpa.slice.ExecutorServiceValue;
|
||||||
|
import org.apache.openjpa.slice.ProductDerivation;
|
||||||
import org.apache.openjpa.slice.Slice;
|
import org.apache.openjpa.slice.Slice;
|
||||||
import org.apache.openjpa.util.UserException;
|
import org.apache.openjpa.util.UserException;
|
||||||
|
|
||||||
|
@ -76,10 +77,10 @@ public class DistributedJDBCConfigurationImpl extends JDBCConfigurationImpl
|
||||||
protected ExecutorServiceValue executorServicePlugin;
|
protected ExecutorServiceValue executorServicePlugin;
|
||||||
protected PluginValue distributionPolicyPlugin;
|
protected PluginValue distributionPolicyPlugin;
|
||||||
|
|
||||||
public static final String PREFIX_SLICE = "openjpa.slice.";
|
|
||||||
public static final String PREFIX_OPENJPA = "openjpa.";
|
|
||||||
public static final String REGEX_DOT = "\\.";
|
|
||||||
public static final String DOT = ".";
|
public static final String DOT = ".";
|
||||||
|
public static final String REGEX_DOT = "\\.";
|
||||||
|
public static final String PREFIX_SLICE = ProductDerivation.PREFIX_SLICE + DOT;
|
||||||
|
public static final String PREFIX_OPENJPA = "openjpa.";
|
||||||
private static Localizer _loc =
|
private static Localizer _loc =
|
||||||
Localizer.forPackage(DistributedJDBCConfigurationImpl.class);
|
Localizer.forPackage(DistributedJDBCConfigurationImpl.class);
|
||||||
|
|
||||||
|
@ -322,10 +323,11 @@ public class DistributedJDBCConfigurationImpl extends JDBCConfigurationImpl
|
||||||
if (sliceNames.isEmpty()) {
|
if (sliceNames.isEmpty()) {
|
||||||
throw new UserException(_loc.get("slice-none-configured"));
|
throw new UserException(_loc.get("slice-none-configured"));
|
||||||
}
|
}
|
||||||
|
String unit = getPersistenceUnitName(original);
|
||||||
for (String key : sliceNames) {
|
for (String key : sliceNames) {
|
||||||
JDBCConfiguration child = new JDBCConfigurationImpl();
|
JDBCConfiguration child = new JDBCConfigurationImpl();
|
||||||
child.fromProperties(createSliceProperties(original, key));
|
child.fromProperties(createSliceProperties(original, key));
|
||||||
child.setId(key);
|
child.setId(unit+DOT+key);
|
||||||
Slice slice = new Slice(key, child);
|
Slice slice = new Slice(key, child);
|
||||||
_slices.add(slice);
|
_slices.add(slice);
|
||||||
if (log.isTraceEnabled())
|
if (log.isTraceEnabled())
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.openjpa.slice.jdbc;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -61,6 +62,7 @@ import org.apache.openjpa.lib.util.Localizer;
|
||||||
import org.apache.openjpa.meta.ClassMetaData;
|
import org.apache.openjpa.meta.ClassMetaData;
|
||||||
import org.apache.openjpa.meta.FieldMetaData;
|
import org.apache.openjpa.meta.FieldMetaData;
|
||||||
import org.apache.openjpa.slice.DistributionPolicy;
|
import org.apache.openjpa.slice.DistributionPolicy;
|
||||||
|
import org.apache.openjpa.slice.ProductDerivation;
|
||||||
import org.apache.openjpa.slice.transaction.DistributedNaiveTransaction;
|
import org.apache.openjpa.slice.transaction.DistributedNaiveTransaction;
|
||||||
import org.apache.openjpa.slice.transaction.DistributedTransactionManager;
|
import org.apache.openjpa.slice.transaction.DistributedTransactionManager;
|
||||||
import org.apache.openjpa.slice.transaction.NaiveTransactionManager;
|
import org.apache.openjpa.slice.transaction.NaiveTransactionManager;
|
||||||
|
@ -275,7 +277,8 @@ class DistributedStoreManager extends JDBCStoreManager {
|
||||||
boolean subclasses, FetchConfiguration fetch) {
|
boolean subclasses, FetchConfiguration fetch) {
|
||||||
ResultObjectProvider[] tmp = new ResultObjectProvider[_slices.size()];
|
ResultObjectProvider[] tmp = new ResultObjectProvider[_slices.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (SliceStoreManager slice : _slices) {
|
List<SliceStoreManager> targets = getTargets(fetch);
|
||||||
|
for (SliceStoreManager slice : targets) {
|
||||||
tmp[i++] = slice.executeExtent(meta, subclasses, fetch);
|
tmp[i++] = slice.executeExtent(meta, subclasses, fetch);
|
||||||
}
|
}
|
||||||
return new MergedResultObjectProvider(tmp);
|
return new MergedResultObjectProvider(tmp);
|
||||||
|
@ -371,7 +374,8 @@ class DistributedStoreManager extends JDBCStoreManager {
|
||||||
return lookup(slice).initialize(sm, state, fetch, edata);
|
return lookup(slice).initialize(sm, state, fetch, edata);
|
||||||
}
|
}
|
||||||
// not a part of Query result load. Look into the slices till found
|
// not a part of Query result load. Look into the slices till found
|
||||||
for (SliceStoreManager slice : _slices) {
|
List<SliceStoreManager> targets = getTargets(fetch);
|
||||||
|
for (SliceStoreManager slice : targets) {
|
||||||
if (slice.initialize(sm, state, fetch, edata)) {
|
if (slice.initialize(sm, state, fetch, edata)) {
|
||||||
sm.setImplData(slice.getName(), true);
|
sm.setImplData(slice.getName(), true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -502,6 +506,31 @@ class DistributedStoreManager extends JDBCStoreManager {
|
||||||
return new RefCountConnection(con);
|
return new RefCountConnection(con);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of slices mentioned as
|
||||||
|
* {@link ProductDerivation#HINT_TARGET hint} of the given
|
||||||
|
* {@link FetchConfiguration#getHint(String) fetch configuration}.
|
||||||
|
*
|
||||||
|
* @return all active slices if a) the hint is not specified or b) a null
|
||||||
|
* value or c) a non-String or d) matches no active slice.
|
||||||
|
*/
|
||||||
|
List<SliceStoreManager> getTargets(FetchConfiguration fetch) {
|
||||||
|
if (fetch == null)
|
||||||
|
return _slices;
|
||||||
|
Object hint = fetch.getHint(ProductDerivation.HINT_TARGET);
|
||||||
|
if (hint == null || !(hint instanceof String))
|
||||||
|
return _slices;
|
||||||
|
List<String> targetNames = Arrays.asList(hint.toString().split("\\,"));
|
||||||
|
List<SliceStoreManager> targets = new ArrayList<SliceStoreManager>();
|
||||||
|
for (SliceStoreManager slice : _slices) {
|
||||||
|
if (targetNames.contains(slice.getName()))
|
||||||
|
targets.add(slice);
|
||||||
|
}
|
||||||
|
if (targets.isEmpty())
|
||||||
|
return _slices;
|
||||||
|
return targets;
|
||||||
|
}
|
||||||
|
|
||||||
private static class Flusher implements Callable<Collection> {
|
private static class Flusher implements Callable<Collection> {
|
||||||
final SliceStoreManager store;
|
final SliceStoreManager store;
|
||||||
final Collection toFlush;
|
final Collection toFlush;
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.util.concurrent.Future;
|
||||||
import org.apache.openjpa.jdbc.kernel.JDBCStore;
|
import org.apache.openjpa.jdbc.kernel.JDBCStore;
|
||||||
import org.apache.openjpa.jdbc.kernel.JDBCStoreQuery;
|
import org.apache.openjpa.jdbc.kernel.JDBCStoreQuery;
|
||||||
import org.apache.openjpa.kernel.ExpressionStoreQuery;
|
import org.apache.openjpa.kernel.ExpressionStoreQuery;
|
||||||
|
import org.apache.openjpa.kernel.FetchConfiguration;
|
||||||
import org.apache.openjpa.kernel.OrderingMergedResultObjectProvider;
|
import org.apache.openjpa.kernel.OrderingMergedResultObjectProvider;
|
||||||
import org.apache.openjpa.kernel.QueryContext;
|
import org.apache.openjpa.kernel.QueryContext;
|
||||||
import org.apache.openjpa.kernel.StoreQuery;
|
import org.apache.openjpa.kernel.StoreQuery;
|
||||||
|
@ -37,6 +38,7 @@ import org.apache.openjpa.lib.rop.MergedResultObjectProvider;
|
||||||
import org.apache.openjpa.lib.rop.RangeResultObjectProvider;
|
import org.apache.openjpa.lib.rop.RangeResultObjectProvider;
|
||||||
import org.apache.openjpa.lib.rop.ResultObjectProvider;
|
import org.apache.openjpa.lib.rop.ResultObjectProvider;
|
||||||
import org.apache.openjpa.meta.ClassMetaData;
|
import org.apache.openjpa.meta.ClassMetaData;
|
||||||
|
import org.apache.openjpa.slice.ProductDerivation;
|
||||||
import org.apache.openjpa.util.StoreException;
|
import org.apache.openjpa.util.StoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,7 +65,13 @@ class DistributedStoreQuery extends JDBCStoreQuery {
|
||||||
public Executor newDataStoreExecutor(ClassMetaData meta, boolean subs) {
|
public Executor newDataStoreExecutor(ClassMetaData meta, boolean subs) {
|
||||||
ParallelExecutor ex = new ParallelExecutor(this, meta, subs, _parser,
|
ParallelExecutor ex = new ParallelExecutor(this, meta, subs, _parser,
|
||||||
ctx.getCompilation());
|
ctx.getCompilation());
|
||||||
|
|
||||||
|
FetchConfiguration fetch = getContext().getFetchConfiguration();
|
||||||
|
DistributedStoreManager store = (DistributedStoreManager)getContext()
|
||||||
|
.getStoreContext().getStoreManager().getInnermostDelegate();
|
||||||
|
List<SliceStoreManager> targets = store.getTargets(fetch);
|
||||||
for (StoreQuery q:_queries) {
|
for (StoreQuery q:_queries) {
|
||||||
|
if (targets.contains(((JDBCStoreQuery)q).getStore()))
|
||||||
ex.addExecutor(q.newDataStoreExecutor(meta, subs));
|
ex.addExecutor(q.newDataStoreExecutor(meta, subs));
|
||||||
}
|
}
|
||||||
return ex;
|
return ex;
|
||||||
|
|
|
@ -215,10 +215,8 @@ public abstract class PersistenceTestCase
|
||||||
if (!meta.isMapped() || meta.isEmbeddedOnly()
|
if (!meta.isMapped() || meta.isEmbeddedOnly()
|
||||||
|| Modifier.isAbstract(meta.getDescribedType().getModifiers()))
|
|| Modifier.isAbstract(meta.getDescribedType().getModifiers()))
|
||||||
continue;
|
continue;
|
||||||
List all = em.createQuery("SELECT o FROM " + meta.getTypeAlias() + " o").
|
em.createQuery("DELETE FROM " + meta.getTypeAlias() + " o").
|
||||||
getResultList();
|
executeUpdate();
|
||||||
for (Object pc:all)
|
|
||||||
em.remove(pc);
|
|
||||||
}
|
}
|
||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
em.close();
|
em.close();
|
||||||
|
|
|
@ -18,11 +18,14 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.openjpa.slice;
|
package org.apache.openjpa.slice;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
|
|
||||||
|
import org.apache.openjpa.persistence.OpenJPAEntityManager;
|
||||||
import org.apache.openjpa.slice.SlicePersistence;
|
import org.apache.openjpa.slice.SlicePersistence;
|
||||||
|
|
||||||
public class TestQuery extends SliceTestCase {
|
public class TestQuery extends SliceTestCase {
|
||||||
|
@ -83,6 +86,21 @@ public class TestQuery extends SliceTestCase {
|
||||||
assertEquals(limit, result.size());
|
assertEquals(limit, result.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testHint() {
|
||||||
|
List<String> targets = new ArrayList<String>();
|
||||||
|
targets.add("Even");
|
||||||
|
EntityManager em = emf.createEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
Query query = em.createQuery("SELECT p FROM PObject p");
|
||||||
|
query.setHint(ProductDerivation.HINT_TARGET, "Even");
|
||||||
|
List result = query.getResultList();
|
||||||
|
for (Object pc : result) {
|
||||||
|
String slice = SlicePersistence.getSlice(pc);
|
||||||
|
assertTrue(targets.contains(slice));
|
||||||
|
}
|
||||||
|
em.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
|
||||||
protected String getPersistenceUnitName() {
|
protected String getPersistenceUnitName() {
|
||||||
return "ordering";
|
return "ordering";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue