
com.hazelcast.map.impl.query.QueryResult Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2008-2024, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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 com.hazelcast.map.impl.query;
import com.hazelcast.map.QueryResultSizeExceededException;
import com.hazelcast.map.impl.MapDataSerializerHook;
import com.hazelcast.nio.ObjectDataInput;
import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.internal.serialization.Data;
import com.hazelcast.projection.Projection;
import com.hazelcast.query.PagingPredicate;
import com.hazelcast.query.impl.QueryableEntry;
import com.hazelcast.internal.serialization.SerializationService;
import com.hazelcast.internal.util.IterationType;
import com.hazelcast.internal.util.SortingUtil;
import com.hazelcast.internal.util.collection.PartitionIdSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import static com.hazelcast.internal.serialization.impl.SerializationUtil.readNullablePartitionIdSet;
import static com.hazelcast.internal.serialization.impl.SerializationUtil.writeNullablePartitionIdSet;
/**
* Represents a result of a query execution in the form of an iterable
* collection of {@link QueryResultRow rows}.
*
* There are two modes of result construction, the choice is
* controlled by the {@code orderAndLimitExpected} parameter:
*
*
* - When {@code orderAndLimitExpected} is {@code true}, this indicates that
* the call to the {@link #orderAndLimit} method is expected on behalf of the
* {@link PagingPredicate paging predicate} involved in the query. In this case,
* the intermediate result is represented as a collection of {@link
* QueryableEntry queryable entries} to allow the comparison of the items using
* the comparator of the paging predicate. After the call to {@link
* #completeConstruction}, all the queryable entries are converted to {@link
* QueryResultRow rows} and the result is ready to be provided to the client.
*
*
- When {@code orderAndLimitExpected} is {@code false}, this indicates that
* no calls to the {@link #orderAndLimit} method are expected. In this case, the
* intermediate result is represented directly as a collection of {@link
* QueryResultRow rows} and no further conversion is performed.
*
*/
public class QueryResult implements Result, Iterable {
private List rows = new ArrayList();
private PartitionIdSet partitionIds;
private IterationType iterationType;
private final transient SerializationService serializationService;
private final transient long resultLimit;
private final transient boolean orderAndLimitExpected;
private final transient Projection projection;
private transient long resultSize;
/**
* Constructs an empty result for the purposes of deserialization.
*/
public QueryResult() {
serializationService = null;
orderAndLimitExpected = false;
resultLimit = Long.MAX_VALUE;
projection = null;
}
/**
* Constructs an empty result.
*
* @param iterationType the iteration type of the query for which
* this result is constructed for.
* @param projection the projection of the query for which this
* result is constructed for.
* @param serializationService the serialization service associated with
* the query for which this result is
* constructed for.
* @param resultLimit the upper limit on the number of items that
* can be {@link #add added} to this result.
* @param orderAndLimitExpected the flag to signal that the call to the
* {@link #orderAndLimit} method is expected,
* see the class javadoc for more details.
*/
public QueryResult(IterationType iterationType, Projection projection, SerializationService serializationService,
long resultLimit, boolean orderAndLimitExpected) {
this.iterationType = iterationType;
this.projection = projection;
this.serializationService = serializationService;
this.resultLimit = resultLimit;
this.orderAndLimitExpected = orderAndLimitExpected;
}
// for testing
IterationType getIterationType() {
return iterationType;
}
@Override
public Iterator iterator() {
return rows.iterator();
}
/**
* @return the size of this result.
*/
public int size() {
return rows.size();
}
/**
* @return {@code true} if this result is empty, {@code false} otherwise.
**/
public boolean isEmpty() {
return rows.isEmpty();
}
/**
* Adds the given row into this result.
*
* @param row the row to add.
*/
public void addRow(QueryResultRow row) {
rows.add(row);
}
/**
* {@inheritDoc}
*
* @throws QueryResultSizeExceededException if the size of this result
* exceeds the result size limit.
*/
@Override
public void add(QueryableEntry entry) {
if (++resultSize > resultLimit) {
throw new QueryResultSizeExceededException();
}
rows.add(orderAndLimitExpected ? entry : convertEntryToRow(entry));
}
@Override
public QueryResult createSubResult() {
return new QueryResult(iterationType, projection, serializationService, resultLimit, orderAndLimitExpected);
}
@Override
public void orderAndLimit(PagingPredicate pagingPredicate, Map.Entry nearestAnchorEntry) {
rows = SortingUtil.getSortedSubList(rows, pagingPredicate, nearestAnchorEntry);
}
@Override
public void completeConstruction(PartitionIdSet partitionIds) {
setPartitionIds(partitionIds);
if (orderAndLimitExpected) {
for (ListIterator iterator = rows.listIterator(); iterator.hasNext(); ) {
iterator.set(convertEntryToRow((QueryableEntry) iterator.next()));
}
}
}
private Data getValueData(QueryableEntry entry) {
if (projection != null) {
return serializationService.toData(projection.transform(entry));
} else {
return entry.getValueData();
}
}
@Override
public PartitionIdSet getPartitionIds() {
return partitionIds;
}
@Override
public void combine(QueryResult result) {
PartitionIdSet otherPartitionIds = result.getPartitionIds();
if (otherPartitionIds == null) {
return;
}
if (partitionIds == null) {
partitionIds = new PartitionIdSet(otherPartitionIds);
} else {
partitionIds.addAll(otherPartitionIds);
}
rows.addAll(result.rows);
}
@Override
public void onCombineFinished() {
}
@Override
public void setPartitionIds(PartitionIdSet partitionIds) {
this.partitionIds = new PartitionIdSet(partitionIds);
}
/**
* @return the rows of this result.
*/
public List getRows() {
return rows;
}
@Override
public int getFactoryId() {
return MapDataSerializerHook.F_ID;
}
@Override
public int getClassId() {
return MapDataSerializerHook.QUERY_RESULT;
}
@Override
public void writeData(ObjectDataOutput out) throws IOException {
writeNullablePartitionIdSet(partitionIds, out);
out.writeByte(iterationType.getId());
int resultSize = rows.size();
out.writeInt(resultSize);
if (resultSize > 0) {
for (QueryResultRow row : (List) rows) {
row.writeData(out);
}
}
}
@Override
public void readData(ObjectDataInput in) throws IOException {
partitionIds = readNullablePartitionIdSet(in);
iterationType = IterationType.getById(in.readByte());
int resultSize = in.readInt();
if (resultSize > 0) {
for (int i = 0; i < resultSize; i++) {
QueryResultRow row = new QueryResultRow();
row.readData(in);
rows.add(row);
}
}
}
private QueryResultRow convertEntryToRow(QueryableEntry entry) {
Data key = null;
Data value = null;
switch (iterationType) {
case KEY:
key = entry.getKeyData();
break;
case VALUE:
value = getValueData(entry);
break;
case ENTRY:
key = entry.getKeyData();
value = entry.getValueData();
break;
default:
throw new IllegalStateException("Unknown iterationType:" + iterationType);
}
return new QueryResultRow(key, value);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy