blob: 75ce930230087726e442471469d94873539baf47 [file] [log] [blame]
/*
* 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 java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.apache.geode.cache.query.types.StructType;
/**
* This is a helper class which provides information on how an index data be used so as to make it
* compatible with the query.
*/
class IndexConditioningHelper {
/**
* boolean if true implies that the index results need to be iterated so as to make it compatible
* with from clause. Shuffling may be needed for any of the following reasons: 1) Match level not
* zero ( implying index result expansion or cutdown) 2) Match level zero , but the relative
* positions of iterators in the List of iterators for the group not matching the positions in the
* index result StructBag 3) Iter operand is not null. *
*
*/
// If shuffling is not needed , then it can be bcoz of two reasons
// 1) The Index results is a ResultSet & match level is zero ( in that case we
// don't have to do anything)
// 2) The Index results is a StructBag with match level as zero & inddex
// fields matching
// the order of RuntimeIterators. In that case we just have to change the
// StructType of the StructBag
boolean shufflingNeeded = true;
/**
* An arary of RuntimeIterators whose size is equal to the number of fields in the Index results.
* It identifies the RuntimeIterator for the field in the Index Results. Thus the Runtime Iterator
* at position 0 will be that for field 0 in the index result & so on. For those index fields
* which do not have a Runtime Iterator assosciated , the value is null (This is the case if index
* results require cut down)
*/
RuntimeIterator[] indexFieldToItrsMapping = null;
/**
* The List containing RuntimeIterators to which the index results need to be expanded This will
* usually be Final List of RuntimeIterators - RuntimeIteratosr already accounted for in the index
* results
*/
// The default is initialized as empty List rather than null to avoid
// Null Pointer Exception in the function
// getconditionedRelationshipIndexResults
List expansionList = Collections.emptyList();
/**
* The List containing RuntimeIterators which define the final SelectResults after the relevant
* expansion/cutdown of index results
*/
// Though in case of single index usage , if no shuffling is needed (
// exact match) we
// do not need finalList , but it is used in relation ship index , even if
// match level is zero.
// So we should never leave it as null
List finalList = null;
/**
* This is the List of RuntimeIterators which gets created only if the index resulst require a
* cutdown. In such cases , it identifies those Runtime Iterators of Index Results which will be
* selected to form the result tuple. The RuntimeIterators in this List will have corresponding
* fields in the resultset obtained from Index usage. This List will be populated only if there
* exists fields in index resultset which will not be selected.If all the fields of index
* resultset will be used , then this List should be null or empty. It is used in preventing
* unnecessary expansion of same type, when a similar expansion has already occured. as for eg
*
* consider a index result containing 3 fields field1 field2 & field3 . Assume that field3 is for
* cutdown. Since the expansion iterators can either be independent of all the fields in the index
* result or at the max be dependent on field1 & field2, we should expand for a given combination
* of field1 & field2 , only once ( as we have resulst as Set, we can only have unique entries)
* ie. suppose a index result tuple has values ( 1,2 , 3 ) & ( 1,2,4) , we should expand only once
* ( as field with value 3 & 4 are to be discarded).
*/
/*
* Below Can be null or empty collections if the match level is exact & no shuffling needed
*/
List checkList = null;
/**
* This field is meaningful iff the match level is zero, no shuffling needed & there exists a
* StructBag (& not a ResultBag)
*/
StructType structType = null;
/**
* Independent Iterator for the Group to which the Path expression belongs to
*/
RuntimeIterator indpndntItr = null;
/**
* Indexnfo object for the path expression
*/
IndexInfo indxInfo = null;
IndexConditioningHelper(IndexInfo indexInfo, ExecutionContext context, int indexFieldsSize,
boolean completeExpansion, CompiledValue iterOperands, RuntimeIterator grpIndpndntItr) {
/*
* First obtain the match level of index resultset. If the match level happens to be zero , this
* implies that we just have to change the StructType ( again if only the Index resultset is a
* StructBag). If the match level is zero & expand to to top level flag is true & iff the total
* no. of iterators in current scope is greater than the no. of fields in StructBag , then only
* we need to do any expansion. The grpIndpndtItr passed can be null if the where clause
* comprises of just this condition. However if it is invoked from GroupJunction , it will be
* not null
*
*/
this.indxInfo = indexInfo;
List grpItrs = null;
int size = indexInfo.mapping.length;
this.indpndntItr = grpIndpndntItr;
this.indexFieldToItrsMapping = new RuntimeIterator[indexFieldsSize];
// Obtain the grpIndpndt iterator if it is passed as null
if (this.indpndntItr == null) {
Set set1 = new HashSet();
context.computeUltimateDependencies(indexInfo._path, set1);
Support.Assert(set1.size() == 1,
" Since we are in Indexed Evaluate that means there has to be exactly one independent iterator for this compiled comparison");
// The ultimate independent RuntimeIterator
this.indpndntItr = (RuntimeIterator) set1.iterator().next();
Support.Assert(
this.indpndntItr.getScopeID() == context.currentScope()
.getScopeID()/* context.getScopeCount() */,
" Since we are in Indexed Evaluate that means the current scope count & indpenedent iterator's scope count should match");
}
if (indexInfo._matchLevel == 0
&& (!completeExpansion || context.getCurrentIterators().size() == size)) {
// Don't do anything , just change the StructType if the set is
// structset.
if (size > 1) {
// The Index resultset is a structType.
Support.Assert(indexInfo._index.getResultSetType() instanceof StructType,
" If the match level is zero & the size of mapping array is 1 then Index is surely ResultBag else StructBag");
// The independent iterator is added as the first element
grpItrs = context.getCurrScopeDpndntItrsBasedOnSingleIndpndntItr(this.indpndntItr);
// Check if reshuffling is needed or just changing the struct
// type will suffice
boolean isReshufflingNeeded = false;
int pos = -1;
for (int i = 0; i < size; ++i) {
pos = indexInfo.mapping[i];
isReshufflingNeeded = isReshufflingNeeded || (pos != (i + 1));
this.indexFieldToItrsMapping[pos - 1] = (RuntimeIterator) grpItrs.get(i);
}
this.finalList = grpItrs;
// Even if Reshuffle is not need but if the iter conditions are
// present we need to do evaluation
// We can avoid iterating over the set iff reshuffling is not needed &
// there is no iter eval condition
if (isReshufflingNeeded || iterOperands != null) {
// this.expansionList = Collections.EMPTY_LIST;
this.checkList = null;
// indexReults = QueryUtils.cutDownAndExpandIndexResults(indexReults,
// indexFieldToItrsMapping, Collections.EMPTY_LIST, grpItrs,
// context, Collections.EMPTY_LIST, iterOperands);
} else {
this.structType = QueryUtils.createStructTypeForRuntimeIterators(grpItrs);
// indexReults.setElementType(structType);
// Shuffling is not needed. Index results is a StructBag
// with match level zero & no expansion needed & index fields map
// with the RuntimeIterators. But we need to change the StructType
// of the StructBag
this.shufflingNeeded = false;
}
} else {
// The finalList should not be left uninitialized, & if the match
// level is zero
// & the Index Results is a ResultBag ( & not an StructBag ) implying
// indexFieldsSize of
// 1 , then the final List should contain only the independent iterator
this.finalList = new ArrayList();
this.finalList.add(this.indpndntItr);
Support.Assert(this.indexFieldToItrsMapping.length == 1,
"In this else block , it should be guaranteed that there exists only one iterator in query as well as index from clause & that should be nothing but the independent RuntimeIterator of the group ");
this.indexFieldToItrsMapping[0] = this.indpndntItr;
// Shuffling is needed if iter operand is not null even if index results is a
// ResultSet
// with match level zero & no expansion needed
this.shufflingNeeded = (iterOperands != null);
}
} else {
// There is some expansion or truncation needed on the data
// obtained from index.Identify a the iterators belonging to this group
// The independent iterator is added as the first element
grpItrs = context.getCurrScopeDpndntItrsBasedOnSingleIndpndntItr(this.indpndntItr);
// Create an array of RuntimeIterators which map to the fields of the
// Index set.
// For those fields which do not have corresponding RuntimeIterator , keep
// it as null;
int pos = -1;
this.finalList = completeExpansion ? context.getCurrentIterators() : grpItrs;
// This is the List of runtimeIterators which have corresponding fields
// in the resultset obtained from Index usage. This List will be populated
// only if there exists fields in index resultset which will not be
// selected
// If all the fields of index resultset will be used , then this List
// should
// be null or empty
this.checkList = new ArrayList();
// This List contains the RuntimeIterators which are missing from
// index resultset but are present in the final iterators
this.expansionList = new LinkedList(finalList);
RuntimeIterator tempItr = null;
// boolean cutDownNeeded = false;
int unMappedFields = indexFieldsSize;
for (int i = 0; i < size; ++i) {
pos = indexInfo.mapping[i];
if (pos > 0) {
tempItr = (RuntimeIterator) grpItrs.get(i);
this.indexFieldToItrsMapping[pos - 1] = tempItr;
this.expansionList.remove(tempItr);
this.checkList.add(tempItr);
--unMappedFields;
}
}
boolean cutDownNeeded = unMappedFields > 0;
if (!cutDownNeeded)
this.checkList = null;
/*
* indexReults = QueryUtils.cutDownAndExpandIndexResults(indexReults, indexFieldToItrsMapping,
* expansionList, finalList, context, checkList, iterOperands);
*/
}
}
}