Author: desruisseaux
Date: Thu Apr 21 10:23:50 2016
New Revision: 1740276
URL: http://svn.apache.org/viewvc?rev=1740276&view=rev
Log:
Add limited caching in CoordinateOperationFactory.
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java?rev=1740276&r1=1740275&r2=1740276&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
[UTF-8] Thu Apr 21 10:23:50 2016
@@ -59,7 +59,7 @@ final class CRSPair {
*/
@Override
public int hashCode() {
- return sourceCRS.hashCode() * 31 + targetCRS.hashCode();
+ return Objects.hashCode(sourceCRS) * 31 + Objects.hashCode(targetCRS);
}
/**
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java?rev=1740276&r1=1740275&r2=1740276&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
[UTF-8] Thu Apr 21 10:23:50 2016
@@ -146,6 +146,11 @@ public class CoordinateOperationFinder e
private final Map<CRSPair,Boolean> previousSearches;
/**
+ * Whether this finder instance is allowed to use {@link
DefaultCoordinateOperationFactory#cache}.
+ */
+ private final boolean useCache;
+
+ /**
* Creates a new instance for the given factory and context.
*
* @param registry the factory to use for creating operations as defined
by authority, or {@code null} if none.
@@ -160,6 +165,7 @@ public class CoordinateOperationFinder e
super(registry, factory, context);
identifierOfStepCRS = new HashMap<>(8);
previousSearches = new HashMap<>(8);
+ useCache = (context == null) && (factory == factorySIS);
}
/**
@@ -190,13 +196,31 @@ public class CoordinateOperationFinder e
{
ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
- if (!previousSearches.isEmpty()) {
- // TODO: verify here if the path is defined in EPSG database.
+ if (equalsIgnoreMetadata(sourceCRS, targetCRS)) try {
+ return createFromAffineTransform(AXIS_CHANGES, sourceCRS,
targetCRS,
+
CoordinateSystems.swapAndScaleAxes(sourceCRS.getCoordinateSystem(),
targetCRS.getCoordinateSystem()));
+ } catch (IllegalArgumentException | ConversionException e) {
+ throw new
FactoryException(Errors.format(Errors.Keys.CanNotInstantiate_1, new
CRSPair(sourceCRS, targetCRS)), e);
}
+ /*
+ * If this method is invoked recursively, verify if the requested
operation is already in the cache.
+ * We do not perform this verification on the first invocation because
it was already verified by
+ * DefaultCoordinateOperationFactory.createOperation(…). We do not
block if the operation is in
+ * process of being computed in another thread because of the risk of
deadlock. If the operation
+ * is not in the cache, store the keys in our internal map for
preventing infinite recursivity.
+ */
final CRSPair key = new CRSPair(sourceCRS, targetCRS);
+ if (useCache && !previousSearches.isEmpty()) {
+ final CoordinateOperation op = factorySIS.cache.peek(key);
+ if (op != null) return op;
+ }
if (previousSearches.put(key, Boolean.TRUE) != null) {
throw new
FactoryException(Errors.format(Errors.Keys.RecursiveCreateCallForCode_2,
CoordinateOperation.class, key));
}
+ /*
+ * If the user did not specified an area of interest, use the domain
of validity of the CRS.
+ * Then verify in the EPSG dataset if the operation is explicitely
defined by an authority.
+ */
GeographicBoundingBox bbox =
Extents.getGeographicBoundingBox(areaOfInterest);
if (bbox == null) {
bbox =
Extents.intersection(CRS.getGeographicBoundingBox(sourceCRS),
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1740276&r1=1740275&r2=1740276&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
[UTF-8] Thu Apr 21 10:23:50 2016
@@ -44,6 +44,7 @@ import org.apache.sis.referencing.factor
import
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
import org.apache.sis.util.collection.WeakHashSet;
import org.apache.sis.util.collection.Containers;
+import org.apache.sis.util.collection.Cache;
import org.apache.sis.util.iso.AbstractFactory;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
@@ -121,10 +122,21 @@ public class DefaultCoordinateOperationF
/**
* Weak references to existing objects.
* This set is used in order to return a pre-existing object instead of
creating a new one.
+ * This apply to object created explicitly, not to coordinate operations
inferred by a call
+ * to {@link #createOperation(CoordinateReferenceSystem,
CoordinateReferenceSystem)}.
*/
private final WeakHashSet<IdentifiedObject> pool;
/**
+ * The cache of coordinate operations found for a given pair of source and
target CRS.
+ * If current implementation, we cache only operations found without
context (otherwise
+ * we would need to take in account the area of interest and desired
accuracy in the key).
+ *
+ * @see #createOperation(CoordinateReferenceSystem,
CoordinateReferenceSystem, CoordinateOperationContext)
+ */
+ final Cache<CRSPair,CoordinateOperation> cache;
+
+ /**
* Constructs a factory with no default properties.
*/
public DefaultCoordinateOperationFactory() {
@@ -167,6 +179,7 @@ public class DefaultCoordinateOperationF
mtFactory = factory;
}
pool = new WeakHashSet<>(IdentifiedObject.class);
+ cache = new Cache<>(12, 50, true);
}
/**
@@ -699,9 +712,32 @@ next: for (int i=components.size(); --
final
CoordinateOperationContext context)
throws OperationNotFoundException, FactoryException
{
- final AuthorityFactory registry = USE_EPSG_FACTORY ?
CRS.getAuthorityFactory(Constants.EPSG) : null;
- return new CoordinateOperationFinder((registry instanceof
CoordinateOperationAuthorityFactory) ?
- (CoordinateOperationAuthorityFactory) registry : null, this,
context).createOperation(sourceCRS, targetCRS);
+ final Cache.Handler<CoordinateOperation> handler;
+ CoordinateOperation op;
+ if (context == null) {
+ final CRSPair key = new CRSPair(sourceCRS, targetCRS);
+ op = cache.peek(key);
+ if (op != null) {
+ return op;
+ }
+ handler = cache.lock(key);
+ } else {
+ // We currently do not cache the operation when the result may
depend on the context (see 'this.cache' javadoc).
+ handler = null;
+ op = null;
+ }
+ try {
+ if (handler == null || (op = handler.peek()) == null) {
+ final AuthorityFactory registry = USE_EPSG_FACTORY ?
CRS.getAuthorityFactory(Constants.EPSG) : null;
+ op = new CoordinateOperationFinder((registry instanceof
CoordinateOperationAuthorityFactory) ?
+ (CoordinateOperationAuthorityFactory) registry : null,
this, context).createOperation(sourceCRS, targetCRS);
+ }
+ } finally {
+ if (handler != null) {
+ handler.putAndUnlock(op);
+ }
+ }
+ return op;
}
/**