All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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.internal.serialization.Data;
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 com.hazelcast.map.QueryResultSizeExceededException;
import com.hazelcast.projection.Projection;
import com.hazelcast.query.PagingPredicate;
import com.hazelcast.query.impl.QueryableEntry;
import com.hazelcast.query.impl.predicates.PagingPredicateImpl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

/**
 * 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: * *

    *
  1. 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. * *
  2. 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) { if (pagingPredicate == null || rows.isEmpty()) { return; } PagingPredicateImpl pagingPredicateImpl = (PagingPredicateImpl) pagingPredicate; Comparator comparator = (entry1, entry2) -> SortingUtil.compare(pagingPredicateImpl.getComparator(), pagingPredicateImpl.getIterationType(), entry1, entry2); Collections.sort(rows, comparator); int nearestPage = nearestAnchorEntry.getKey(); int pageSize = pagingPredicate.getPageSize(); int page = pagingPredicate.getPage(); long totalSize = pageSize * ((long) page - nearestPage); if (rows.size() > totalSize) { // it's safe to cast totalSize back to int here since it's limited by the list size rows = rows.subList(0, (int) totalSize); } } @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; } 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