/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package org.apache.geode.cache.query.internal; import org.apache.geode.cache.CacheException; import org.apache.geode.cache.LowMemoryException; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.client.internal.InternalPool; import org.apache.geode.cache.client.internal.ProxyCache; import org.apache.geode.cache.client.internal.ServerProxy; import org.apache.geode.cache.client.internal.UserAttributes; import org.apache.geode.cache.query.*; import org.apache.geode.cache.query.internal.cq.ClientCQ; import org.apache.geode.cache.query.internal.cq.CqService; import org.apache.geode.cache.query.internal.cq.InternalCqQuery; import org.apache.geode.cache.query.internal.index.*; import org.apache.geode.cache.query.internal.parse.OQLLexerTokenTypes; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.cache.ForceReattemptException; import org.apache.geode.internal.cache.InternalCache; import org.apache.geode.internal.cache.LocalRegion; import org.apache.geode.internal.cache.PartitionedRegion; import org.apache.geode.internal.cache.control.MemoryThresholds; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.log4j.LocalizedMessage; import org.apache.logging.log4j.Logger; import java.util.*; import java.util.Map.Entry; /** * @version $Revision: 1.2 $ */ public class DefaultQueryService implements QueryService { private static final Logger logger = LogService.getLogger(); /** * System property to allow query on region with heterogeneous objects. By default its set to * false. */ public static final boolean QUERY_HETEROGENEOUS_OBJECTS = Boolean .valueOf(System.getProperty( DistributionConfig.GEMFIRE_PREFIX + "QueryService.QueryHeterogeneousObjects", "true")) .booleanValue(); public static boolean COPY_ON_READ_AT_ENTRY_LEVEL = Boolean .valueOf(System.getProperty( DistributionConfig.GEMFIRE_PREFIX + "QueryService.CopyOnReadAtEntryLevel", "false")) .booleanValue(); /** Test purpose only */ public static boolean TEST_QUERY_HETEROGENEOUS_OBJECTS = false; private final InternalCache cache; private InternalPool pool; private Map<Region, HashSet<IndexCreationData>> indexDefinitions = Collections.synchronizedMap(new HashMap<Region, HashSet<IndexCreationData>>()); public DefaultQueryService(InternalCache cache) { if (cache == null) throw new IllegalArgumentException( LocalizedStrings.DefaultQueryService_CACHE_MUST_NOT_BE_NULL.toLocalizedString()); this.cache = cache; } /** * Constructs a new <code>Query</code> object. Uses the default namespace, which is the Objects * Context of the current application. * * @return The new <code>Query</code> object. * @throws IllegalArgumentException if the query syntax is invalid. * @see org.apache.geode.cache.query.Query */ public Query newQuery(String queryString) { if (QueryMonitor.isLowMemory()) { String reason = LocalizedStrings.QueryMonitor_LOW_MEMORY_CANCELED_QUERY .toLocalizedString(QueryMonitor.getMemoryUsedDuringLowMemory()); throw new QueryExecutionLowMemoryException(reason); } if (queryString == null) throw new QueryInvalidException( LocalizedStrings.DefaultQueryService_THE_QUERY_STRING_MUST_NOT_BE_NULL .toLocalizedString()); if (queryString.length() == 0) throw new QueryInvalidException( LocalizedStrings.DefaultQueryService_THE_QUERY_STRING_MUST_NOT_BE_EMPTY .toLocalizedString()); ServerProxy serverProxy = pool == null ? null : new ServerProxy(pool); DefaultQuery query = new DefaultQuery(queryString, this.cache, serverProxy != null); query.setServerProxy(serverProxy); return query; } public Query newQuery(String queryString, ProxyCache proxyCache) { Query query = newQuery(queryString); ((DefaultQuery) query).setProxyCache(proxyCache); return query; } public Index createHashIndex(String indexName, String indexedExpression, String fromClause) throws IndexNameConflictException, IndexExistsException, RegionNotFoundException { return createHashIndex(indexName, indexedExpression, fromClause, null); } public Index createHashIndex(String indexName, String indexedExpression, String fromClause, String imports) throws IndexNameConflictException, IndexExistsException, RegionNotFoundException { return createIndex(indexName, IndexType.HASH, indexedExpression, fromClause, imports); } public Index createIndex(String indexName, String indexedExpression, String fromClause) throws IndexNameConflictException, IndexExistsException, RegionNotFoundException { return createIndex(indexName, IndexType.FUNCTIONAL, indexedExpression, fromClause, null); } public Index createIndex(String indexName, String indexedExpression, String fromClause, String imports) throws IndexNameConflictException, IndexExistsException, RegionNotFoundException { return createIndex(indexName, IndexType.FUNCTIONAL, indexedExpression, fromClause, imports); } public Index createKeyIndex(String indexName, String indexedExpression, String fromClause) throws IndexNameConflictException, IndexExistsException, RegionNotFoundException { return createIndex(indexName, IndexType.PRIMARY_KEY, indexedExpression, fromClause, null); } public Index createIndex(String indexName, IndexType indexType, String indexedExpression, String fromClause) throws IndexNameConflictException, IndexExistsException, RegionNotFoundException { return createIndex(indexName, indexType, indexedExpression, fromClause, null); } public Index createIndex(String indexName, IndexType indexType, String indexedExpression, String fromClause, String imports, boolean loadEntries) throws IndexNameConflictException, IndexExistsException, RegionNotFoundException { return createIndex(indexName, indexType, indexedExpression, fromClause, imports, loadEntries, null); } public Index createIndex(String indexName, IndexType indexType, String indexedExpression, String fromClause, String imports, boolean loadEntries, Region region) throws IndexNameConflictException, IndexExistsException, RegionNotFoundException { if (pool != null) { throw new UnsupportedOperationException( "Index creation on the server is not supported from the client."); } PartitionedIndex parIndex = null; if (region == null) { region = getRegionFromPath(imports, fromClause); } RegionAttributes ra = region.getAttributes(); // Asif: If the evistion action is Overflow to disk then do not allow index creation // It is Ok to have index creation if it is persist only mode as data will always // exist in memory // if(ra.getEvictionAttributes().getAction().isOverflowToDisk() ) { // throw new // UnsupportedOperationException(LocalizedStrings.DefaultQueryService_INDEX_CREATION_IS_NOT_SUPPORTED_FOR_REGIONS_WHICH_OVERFLOW_TO_DISK_THE_REGION_INVOLVED_IS_0.toLocalizedString(regionPath)); // } // if its a pr the create index on all of the local buckets. if (((LocalRegion) region).memoryThresholdReached.get() && !MemoryThresholds.isLowMemoryExceptionDisabled()) { LocalRegion lr = (LocalRegion) region; throw new LowMemoryException( LocalizedStrings.ResourceManager_LOW_MEMORY_FOR_INDEX.toLocalizedString(region.getName()), lr.getMemoryThresholdReachedMembers()); } if (region instanceof PartitionedRegion) { try { parIndex = (PartitionedIndex) ((PartitionedRegion) region).createIndex(false, indexType, indexName, indexedExpression, fromClause, imports, loadEntries); } catch (ForceReattemptException ex) { region.getCache().getLoggerI18n().info( LocalizedStrings.DefaultQueryService_EXCEPTION_WHILE_CREATING_INDEX_ON_PR_DEFAULT_QUERY_PROCESSOR, ex); } catch (IndexCreationException exx) { region.getCache().getLoggerI18n().info( LocalizedStrings.DefaultQueryService_EXCEPTION_WHILE_CREATING_INDEX_ON_PR_DEFAULT_QUERY_PROCESSOR, exx); } return parIndex; } else { IndexManager indexManager = IndexUtils.getIndexManager(region, true); Index index = indexManager.createIndex(indexName, indexType, indexedExpression, fromClause, imports, null, null, loadEntries); return index; } } public Index createIndex(String indexName, IndexType indexType, String indexedExpression, String fromClause, String imports) throws IndexNameConflictException, IndexExistsException, RegionNotFoundException { return createIndex(indexName, indexType, indexedExpression, fromClause, imports, true); } private Region getRegionFromPath(String imports, String fromClause) throws RegionNotFoundException { QCompiler compiler = new QCompiler(); if (imports != null) { compiler.compileImports(imports); } List list = compiler.compileFromClause(fromClause); CompiledValue cv = QueryUtils .obtainTheBottomMostCompiledValue(((CompiledIteratorDef) list.get(0)).getCollectionExpr()); String regionPath = null; if (cv.getType() == OQLLexerTokenTypes.RegionPath) { regionPath = ((CompiledRegion) cv).getRegionPath(); } else { throw new RegionNotFoundException( LocalizedStrings.DefaultQueryService_DEFAULTQUERYSERVICECREATEINDEXFIRST_ITERATOR_OF_INDEX_FROM_CLAUSE_DOES_NOT_EVALUATE_TO_A_REGION_PATH_THE_FROM_CLAUSE_USED_FOR_INDEX_CREATION_IS_0 .toLocalizedString(fromClause)); } Region region = cache.getRegion(regionPath); if (region == null) { throw new RegionNotFoundException( LocalizedStrings.DefaultQueryService_REGION_0_NOT_FOUND_FROM_1 .toLocalizedString(new Object[] {regionPath, fromClause})); } return region; } /** * Asif : Gets an exact match index ( match level 0) * * @param regionPath String containing the region name * @param definitions An array of String objects containing canonicalized definitions of * RuntimeIterators. A Canonicalized definition of a RuntimeIterator is the canonicalized * expression obtainded from its underlying collection expression. * @param indexType IndexType object which can be either of type RangeIndex or PrimaryKey Index * @param indexedExpression CompiledValue containing the path expression on which index needs to * be created * @param context ExecutionContext * @return IndexData object * @throws NameResolutionException * @throws TypeMismatchException * @throws AmbiguousNameException */ public IndexData getIndex(String regionPath, String[] definitions, IndexType indexType, CompiledValue indexedExpression, ExecutionContext context) throws AmbiguousNameException, TypeMismatchException, NameResolutionException { Region region = cache.getRegion(regionPath); if (region == null) { return null; } IndexManager indexManager = IndexUtils.getIndexManager(region, true); IndexData indexData = indexManager.getIndex(indexType, definitions, indexedExpression, context); return indexData; } public Index getIndex(Region region, String indexName) { if (pool != null) { throw new UnsupportedOperationException( "Index Operation is not supported on the Server Region."); } // A Partition Region does not have an IndexManager, but it's buckets have. if (region instanceof PartitionedRegion) { return (Index) ((PartitionedRegion) region).getIndex().get(indexName); } else { IndexManager indexManager = IndexUtils.getIndexManager(region, false); if (indexManager == null) return null; return indexManager.getIndex(indexName); } } /** * Asif: Gets a best match index which is available. An index with match level equal to 0 is the * best index to use as it implies that the query from clause iterators belonging to the region * exactly match the index from clause iterators ( the difference in the relative positions of the * iterators do not matter). A match level less than 0 means that number of iteratots in the index * resultset is more than that present in the query from clause and hence index resultset will * need a cutdown. A match level greater than 0 means that there definitely is atleast one * iterator in the query from clause which is more than the index from clause iterators & hence * definitely expansion of index results will be needed. Pls note that a match level greater than * 0 does not imply that index from clause does not have an extra iterator in it , too. Hence a * match level greater than 0 will definitely mean expansion of index results but may also require * a cut down of results . The order of preference is match level 0 , less than 0 and lastly * greater than 0 * * @param regionPath String containing the region name * @param definitions An array of String objects containing canonicalized definitions of * RuntimeIterators. A Canonicalized definition of a RuntimeIterator is the canonicalized * expression obtainded from its underlying collection expression. * @param indexType IndexType object which can be either of type RangeIndex or PrimaryKey Index * @param indexedExpression CompiledValue representing the path expression on which index needs to * be created * @param context ExecutionContext object * @return IndexData object * @throws NameResolutionException * @throws TypeMismatchException * @throws AmbiguousNameException */ public IndexData getBestMatchIndex(String regionPath, String definitions[], IndexType indexType, CompiledValue indexedExpression, ExecutionContext context) throws AmbiguousNameException, TypeMismatchException, NameResolutionException { Region region = cache.getRegion(regionPath); if (region == null) { return null; } // return getBestMatchIndex(region, indexType, definitions, // indexedExpression); IndexManager indexManager = IndexUtils.getIndexManager(region, false); if (indexManager == null) { return null; } return indexManager.getBestMatchIndex(indexType, definitions, indexedExpression, context); } public Collection getIndexes() { ArrayList allIndexes = new ArrayList(); Iterator rootRegions = cache.rootRegions().iterator(); while (rootRegions.hasNext()) { Region region = (Region) rootRegions.next(); Collection indexes = getIndexes(region); if (indexes != null) allIndexes.addAll(indexes); Iterator subRegions = region.subregions(true).iterator(); while (subRegions.hasNext()) { indexes = getIndexes((Region) subRegions.next()); if (indexes != null) allIndexes.addAll(indexes); } } return allIndexes; } public Collection getIndexes(Region region) { if (pool != null) { throw new UnsupportedOperationException( "Index Operation is not supported on the Server Region."); } if (region instanceof PartitionedRegion) { return ((PartitionedRegion) region).getIndexes(); } IndexManager indexManager = IndexUtils.getIndexManager(region, false); if (indexManager == null) return null; return indexManager.getIndexes(); } public Collection getIndexes(Region region, IndexType indexType) { if (pool != null) { throw new UnsupportedOperationException( "Index Operation is not supported on the Server Region."); } IndexManager indexManager = IndexUtils.getIndexManager(region, false); if (indexManager == null) return null; return indexManager.getIndexes(indexType); } public void removeIndex(Index index) { if (pool != null) { throw new UnsupportedOperationException( "Index Operation is not supported on the Server Region."); } Region region = index.getRegion(); if (region instanceof PartitionedRegion) { try { ((PartitionedRegion) region).removeIndex(index, false); } catch (ForceReattemptException ex) { logger.info(LocalizedMessage .create(LocalizedStrings.DefaultQueryService_EXCEPTION_REMOVING_INDEX___0), ex); } return; } // get write lock for indexes in replicated region // for PR lock will be taken in PartitionRegion.removeIndex ((AbstractIndex) index).acquireIndexWriteLockForRemove(); try { IndexManager indexManager = ((LocalRegion) index.getRegion()).getIndexManager(); indexManager.removeIndex(index); } finally { ((AbstractIndex) index).releaseIndexWriteLockForRemove(); } } public void removeIndexes() { if (pool != null) { throw new UnsupportedOperationException( "Index Operation is not supported on the Server Region."); } Iterator rootRegions = cache.rootRegions().iterator(); while (rootRegions.hasNext()) { Region region = (Region) rootRegions.next(); Iterator subRegions = region.subregions(true).iterator(); while (subRegions.hasNext()) { removeIndexes((Region) subRegions.next()); } removeIndexes(region); } } public void removeIndexes(Region region) { if (pool != null) { throw new UnsupportedOperationException( "Index Operation is not supported on the Server Region."); } // removing indexes on paritioned region will reguire sending message and // remvoing all the local indexes on the local bucket regions. if (region instanceof PartitionedRegion) { try { // not remotely orignated ((PartitionedRegion) region).removeIndexes(false); } catch (ForceReattemptException ex) { // will have to throw a proper exception relating to remove index. logger.info(LocalizedMessage .create(LocalizedStrings.DefaultQueryService_EXCEPTION_REMOVING_INDEX___0), ex); } } IndexManager indexManager = IndexUtils.getIndexManager(region, false); if (indexManager == null) return; indexManager.removeIndexes(); } // CqService Related API implementation. /** * Constructs a new continuous query, represented by an instance of CqQuery. The CqQuery is not * executed until the execute method is invoked on the CqQuery. * * @param queryString the OQL query * @param cqAttributes the CqAttributes * @return the newly created CqQuery object * @throws IllegalArgumentException if queryString or cqAttr is null * @throws IllegalStateException if this method is called from a cache server * @throws QueryInvalidException if there is a syntax error in the query * @throws CqException if failed to create cq, failure during creating managing cq metadata info. * E.g.: Query string should refer only one region, join not supported. The query must be * a SELECT statement. DISTINCT queries are not supported. Projections are not supported. * Only one iterator in the FROM clause is supported, and it must be a region path. Bind * parameters in the query are not yet supported. */ public CqQuery newCq(String queryString, CqAttributes cqAttributes) throws QueryInvalidException, CqException { ClientCQ cq = null; try { cq = (ClientCQ) getCqService().newCq(null, queryString, cqAttributes, this.pool, false); } catch (CqExistsException cqe) { // Should not throw in here. if (logger.isDebugEnabled()) { logger.debug("Unable to createCq. Error :{}", cqe.getMessage(), cqe); } } return cq; } /** * Constructs a new continuous query, represented by an instance of CqQuery. The CqQuery is not * executed until the execute method is invoked on the CqQuery. * * @param queryString the OQL query * @param cqAttributes the CqAttributes * @param isDurable true if the CQ is durable * @return the newly created CqQuery object * @throws IllegalArgumentException if queryString or cqAttr is null * @throws IllegalStateException if this method is called from a cache server * @throws QueryInvalidException if there is a syntax error in the query * @throws CqException if failed to create cq, failure during creating managing cq metadata info. * E.g.: Query string should refer only one region, join not supported. The query must be * a SELECT statement. DISTINCT queries are not supported. Projections are not supported. * Only one iterator in the FROM clause is supported, and it must be a region path. Bind * parameters in the query are not yet supported. */ public CqQuery newCq(String queryString, CqAttributes cqAttributes, boolean isDurable) throws QueryInvalidException, CqException { ClientCQ cq = null; try { cq = (ClientCQ) getCqService().newCq(null, queryString, cqAttributes, this.pool, isDurable); } catch (CqExistsException cqe) { // Should not throw in here. if (logger.isDebugEnabled()) { logger.debug("Unable to createCq. Error :{}", cqe.getMessage(), cqe); } } return cq; } /** * Constructs a new named continuous query, represented by an instance of CqQuery. The CqQuery is * not executed, however, until the execute method is invoked on the CqQuery. The name of the * query will be used to identify this query in statistics archival. * * @param cqName the String name for this query * @param queryString the OQL query * @param cqAttributes the CqAttributes * @return the newly created CqQuery object * @throws CqExistsException if a CQ by this name already exists on this client * @throws IllegalArgumentException if queryString or cqAttr is null * @throws IllegalStateException if this method is called from a cache server * @throws QueryInvalidException if there is a syntax error in the query * @throws CqException if failed to create cq, failure during creating managing cq metadata info. * E.g.: Query string should refer only one region, join not supported. The query must be * a SELECT statement. DISTINCT queries are not supported. Projections are not supported. * Only one iterator in the FROM clause is supported, and it must be a region path. Bind * parameters in the query are not yet supported. */ public CqQuery newCq(String cqName, String queryString, CqAttributes cqAttributes) throws QueryInvalidException, CqExistsException, CqException { if (cqName == null) { throw new IllegalArgumentException( LocalizedStrings.DefaultQueryService_CQNAME_MUST_NOT_BE_NULL.toLocalizedString()); } ClientCQ cq = (ClientCQ) getCqService().newCq(cqName, queryString, cqAttributes, this.pool, false); return cq; } /** * Constructs a new named continuous query, represented by an instance of CqQuery. The CqQuery is * not executed, however, until the execute method is invoked on the CqQuery. The name of the * query will be used to identify this query in statistics archival. * * @param cqName the String name for this query * @param queryString the OQL query * @param cqAttributes the CqAttributes * @param isDurable true if the CQ is durable * @return the newly created CqQuery object * @throws CqExistsException if a CQ by this name already exists on this client * @throws IllegalArgumentException if queryString or cqAttr is null * @throws IllegalStateException if this method is called from a cache server * @throws QueryInvalidException if there is a syntax error in the query * @throws CqException if failed to create cq, failure during creating managing cq metadata info. * E.g.: Query string should refer only one region, join not supported. The query must be * a SELECT statement. DISTINCT queries are not supported. Projections are not supported. * Only one iterator in the FROM clause is supported, and it must be a region path. Bind * parameters in the query are not yet supported. */ public CqQuery newCq(String cqName, String queryString, CqAttributes cqAttributes, boolean isDurable) throws QueryInvalidException, CqExistsException, CqException { if (cqName == null) { throw new IllegalArgumentException( LocalizedStrings.DefaultQueryService_CQNAME_MUST_NOT_BE_NULL.toLocalizedString()); } ClientCQ cq = (ClientCQ) getCqService().newCq(cqName, queryString, cqAttributes, this.pool, isDurable); return cq; } /** * Close all CQs executing in this VM, and release resources associated with executing CQs. * CqQuerys created by other VMs are unaffected. * */ public void closeCqs() { try { getCqService().closeAllCqs(true); } catch (CqException cqe) { if (logger.isDebugEnabled()) { logger.debug("Unable to closeAll Cqs. Error :{}", cqe.getMessage(), cqe); } } } /** * Retrieve a CqQuery by name. * * @return the CqQuery or null if not found */ public CqQuery getCq(String cqName) { CqQuery cq = null; try { cq = (CqQuery) getCqService().getCq(cqName); } catch (CqException cqe) { if (logger.isDebugEnabled()) { logger.debug("Unable to getCq. Error :{}", cqe.getMessage(), cqe); } } return cq; } /** * Retrieve all CqQuerys created by this VM. * * @return null if there are no cqs. */ public CqQuery[] getCqs() { CqQuery[] cqs = null; try { return toArray(getCqService().getAllCqs()); } catch (CqException cqe) { if (logger.isDebugEnabled()) { logger.debug("Unable to getAllCqs. Error :{}", cqe.getMessage(), cqe); } } return cqs; } private CqQuery[] toArray(Collection<? extends InternalCqQuery> allCqs) { CqQuery[] cqs = new CqQuery[allCqs.size()]; allCqs.toArray(cqs); return cqs; } /** * Returns all the cq on a given region. */ public CqQuery[] getCqs(final String regionName) throws CqException { return toArray(getCqService().getAllCqs(regionName)); } /** * Starts execution of all the registered continuous queries for this client. This is * complementary to stopCqs. * * @see QueryService#stopCqs() * * @throws CqException if failure to execute CQ. */ public void executeCqs() throws CqException { try { getCqService().executeAllClientCqs(); } catch (CqException cqe) { if (logger.isDebugEnabled()) { logger.debug("Unable to execute all cqs. Error :{}", cqe.getMessage(), cqe); } } } /** * Stops execution of all the continuous queries for this client to become inactive. This is * useful when client needs to control the incoming cq messages during bulk region operations. * * @see QueryService#executeCqs() * * @throws CqException if failure to execute CQ. */ public void stopCqs() throws CqException { try { getCqService().stopAllClientCqs(); } catch (CqException cqe) { if (logger.isDebugEnabled()) { logger.debug("Unable to stop all CQs. Error :{}", cqe.getMessage(), cqe); } } } /** * Starts execution of all the continuous queries registered on the specified region for this * client. This is complementary method to stopCQs(). * * @see QueryService#stopCqs() * * @throws CqException if failure to stop CQs. */ public void executeCqs(String regionName) throws CqException { try { getCqService().executeAllRegionCqs(regionName); } catch (CqException cqe) { if (logger.isDebugEnabled()) { logger.debug("Unable to execute cqs on the specified region. Error :{}", cqe.getMessage(), cqe); } } } /** * Stops execution of all the continuous queries registered on the specified region for this * client. This is useful when client needs to control the incoming cq messages during bulk region * operations. * * @see QueryService#executeCqs() * * @throws CqException if failure to execute CQs. */ public void stopCqs(String regionName) throws CqException { try { getCqService().stopAllRegionCqs(regionName); } catch (CqException cqe) { if (logger.isDebugEnabled()) { logger.debug("Unable to stop cqs on the specified region. Error :{}", cqe.getMessage(), cqe); } } } /** * Get statistics information for this query. * * @return CQ statistics null if the continuous query object not found for the given cqName. */ public CqServiceStatistics getCqStatistics() { CqServiceStatistics stats = null; try { stats = getCqService().getCqStatistics(); } catch (CqException cqe) { if (logger.isDebugEnabled()) { logger.debug("Unable get CQ Statistics. Error :{}", cqe.getMessage(), cqe); } } return stats; } /** * Is the CQ service in a cache server environment * * @return true if cache server, false otherwise */ public boolean isServer() { if (this.cache.getCacheServers().isEmpty()) { return false; } return true; } /** * Close the CQ Service after clean up if any. * */ public void closeCqService() { cache.getCqService().close(); } /** * @return CqService */ public CqService getCqService() throws CqException { CqService service = cache.getCqService(); service.start(); return service; } public void setPool(InternalPool pool) { this.pool = pool; if (logger.isDebugEnabled()) { logger.debug("Setting ServerProxy with the Query Service using the pool :{} ", pool.getName()); } } public List<String> getAllDurableCqsFromServer() throws CqException { if (!isServer()) { if (pool != null) { return getCqService().getAllDurableCqsFromServer(pool); } else { throw new UnsupportedOperationException( "GetAllDurableCQsFromServer requires a pool to be configured."); } } else { // we are a server return Collections.EMPTY_LIST; } } public UserAttributes getUserAttributes(String cqName) { try { return getCqService().getUserAttributes(cqName); } catch (CqException ce) { return null; } } @Override public void defineKeyIndex(String indexName, String indexedExpression, String fromClause) throws RegionNotFoundException { defineIndex(indexName, IndexType.PRIMARY_KEY, indexedExpression, fromClause, null); } @Override public void defineHashIndex(String indexName, String indexedExpression, String fromClause) throws RegionNotFoundException { defineIndex(indexName, IndexType.HASH, indexedExpression, fromClause, null); } @Override public void defineHashIndex(String indexName, String indexedExpression, String fromClause, String imports) throws RegionNotFoundException { defineIndex(indexName, IndexType.HASH, indexedExpression, fromClause, imports); } @Override public void defineIndex(String indexName, String indexedExpression, String fromClause) throws RegionNotFoundException { defineIndex(indexName, IndexType.FUNCTIONAL, indexedExpression, fromClause, null); } @Override public void defineIndex(String indexName, String indexedExpression, String fromClause, String imports) throws RegionNotFoundException { defineIndex(indexName, IndexType.FUNCTIONAL, indexedExpression, fromClause, imports); } public void defineIndex(String indexName, IndexType indexType, String indexedExpression, String fromClause, String imports) throws RegionNotFoundException { IndexCreationData indexData = new IndexCreationData(indexName); indexData.setIndexData(indexType, fromClause, indexedExpression, imports); Region r = getRegionFromPath(imports, fromClause); synchronized (indexDefinitions) { HashSet<IndexCreationData> s = indexDefinitions.get(r); if (s == null) { s = new HashSet<IndexCreationData>(); } s.add(indexData); indexDefinitions.put(r, s); } } @Override public List<Index> createDefinedIndexes() throws MultiIndexCreationException { HashSet<Index> indexes = new HashSet<Index>(); boolean throwException = false; HashMap<String, Exception> exceptionsMap = new HashMap<String, Exception>(); synchronized (indexDefinitions) { for (Entry<Region, HashSet<IndexCreationData>> e : indexDefinitions.entrySet()) { Region region = e.getKey(); HashSet<IndexCreationData> icds = e.getValue(); if (region instanceof PartitionedRegion) { throwException = createDefinedIndexesForPR(indexes, (PartitionedRegion) region, icds, exceptionsMap); } else { throwException = createDefinedIndexesForReplicatedRegion(indexes, region, icds, exceptionsMap); } } } // end sync if (throwException) { throw new MultiIndexCreationException(exceptionsMap); } return new ArrayList<Index>(indexes); } private boolean createDefinedIndexesForPR(HashSet<Index> indexes, PartitionedRegion region, HashSet<IndexCreationData> icds, HashMap<String, Exception> exceptionsMap) { try { indexes.addAll(((PartitionedRegion) region).createIndexes(false, icds)); } catch (IndexCreationException e1) { logger.info( LocalizedMessage.create( LocalizedStrings.DefaultQueryService_EXCEPTION_WHILE_CREATING_INDEX_ON_PR_DEFAULT_QUERY_PROCESSOR), e1); } catch (CacheException e1) { logger.info( LocalizedMessage.create( LocalizedStrings.DefaultQueryService_EXCEPTION_WHILE_CREATING_INDEX_ON_PR_DEFAULT_QUERY_PROCESSOR), e1); return true; } catch (ForceReattemptException e1) { logger.info( LocalizedMessage.create( LocalizedStrings.DefaultQueryService_EXCEPTION_WHILE_CREATING_INDEX_ON_PR_DEFAULT_QUERY_PROCESSOR), e1); return true; } catch (MultiIndexCreationException e) { exceptionsMap.putAll(e.getExceptionsMap()); return true; } return false; } private boolean createDefinedIndexesForReplicatedRegion(HashSet<Index> indexes, Region region, Set<IndexCreationData> icds, HashMap<String, Exception> exceptionsMap) { boolean throwException = false; for (IndexCreationData icd : icds) { try { // First step is creating all the defined indexes. Do this only if // the region is not PR. For PR creation and population is done in // the PartitionedRegion#createDefinedIndexes indexes.add(createIndex(icd.getIndexName(), icd.getIndexType(), icd.getIndexExpression(), icd.getIndexFromClause(), icd.getIndexImportString(), false, region)); } catch (Exception ex) { // If an index creation fails, add the exception to the map and // continue creating rest of the indexes.The failed indexes will // be removed from the IndexManager#indexes map by the createIndex // method so that those indexes will not be populated in the next // step. if (logger.isDebugEnabled()) { logger.debug("Index creation failed, {}, {}", icd.getIndexName(), ex.getMessage(), ex); } exceptionsMap.put(icd.getIndexName(), ex); throwException = true; } } if (IndexManager.testHook != null) { IndexManager.testHook.hook(13); } // Second step is iterating over REs and populating all the created // indexes IndexManager indexManager = IndexUtils.getIndexManager(region, false); if (indexManager == null) { for (IndexCreationData icd : icds) { exceptionsMap.put(icd.getIndexName(), new IndexCreationException("Index Creation Failed due to region destroy")); } return true; } if (indexes.size() > 0) { try { indexManager.populateIndexes(indexes); } catch (MultiIndexCreationException ex) { exceptionsMap.putAll(ex.getExceptionsMap()); throwException = true; } } return throwException; } public boolean clearDefinedIndexes() { this.indexDefinitions.clear(); return true; } public InternalPool getPool() { return pool; } }