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:
Pinaki Poddar 2008-02-14 22:16:45 +00:00
parent caa400cbb3
commit 8a811f69ea
10 changed files with 94 additions and 23 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -27,21 +27,34 @@ 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) {
m.put("slice", DistributedJDBCBrokerFactory.class.getName()); m.put("slice", DistributedJDBCBrokerFactory.class.getName());
} }
public String getConfigurationPrefix() { public String getConfigurationPrefix() {
return "openjpa.slice"; return PREFIX_SLICE;
} }
public int getType() { public int getType() {

View File

@ -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
* *

View File

@ -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())

View File

@ -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;
@ -501,6 +505,31 @@ class DistributedStoreManager extends JDBCStoreManager {
DistributedConnection con = new DistributedConnection(list); DistributedConnection con = new DistributedConnection(list);
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;

View File

@ -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,8 +65,14 @@ 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) {
ex.addExecutor(q.newDataStoreExecutor(meta, subs)); if (targets.contains(((JDBCStoreQuery)q).getStore()))
ex.addExecutor(q.newDataStoreExecutor(meta, subs));
} }
return ex; return ex;
} }

View File

@ -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();

View File

@ -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";
} }