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

org.apache.cassandra.db.SinglePartitionReadQuery Maven / Gradle / Ivy

Go to download

The Apache Cassandra Project develops a highly scalable second-generation distributed database, bringing together Dynamo's fully distributed design and Bigtable's ColumnFamily-based data model.

There is a newer version: 5.0.2
Show newest version
/*
 * 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.cassandra.db;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import com.google.common.collect.Iterables;

import org.apache.commons.lang3.tuple.Pair;

import org.apache.cassandra.db.filter.ClusteringIndexFilter;
import org.apache.cassandra.db.filter.ColumnFilter;
import org.apache.cassandra.db.filter.DataLimits;
import org.apache.cassandra.db.filter.RowFilter;
import org.apache.cassandra.db.partitions.PartitionIterator;
import org.apache.cassandra.db.partitions.UnfilteredPartitionIterator;
import org.apache.cassandra.db.partitions.UnfilteredPartitionIterators;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.service.pager.MultiPartitionPager;
import org.apache.cassandra.service.pager.PagingState;
import org.apache.cassandra.service.pager.QueryPager;
import org.apache.cassandra.service.pager.SinglePartitionPager;
import org.apache.cassandra.transport.ProtocolVersion;

/**
 * A {@code ReadQuery} for a single partition.
 */
public interface SinglePartitionReadQuery extends ReadQuery
{
    public static Group createGroup(TableMetadata metadata,
                                                                        int nowInSec,
                                                                        ColumnFilter columnFilter,
                                                                        RowFilter rowFilter,
                                                                        DataLimits limits,
                                                                        List partitionKeys,
                                                                        ClusteringIndexFilter clusteringIndexFilter)
    {
        return metadata.isVirtual()
             ? VirtualTableSinglePartitionReadQuery.Group.create(metadata, nowInSec, columnFilter, rowFilter, limits, partitionKeys, clusteringIndexFilter)
             : SinglePartitionReadCommand.Group.create(metadata, nowInSec, columnFilter, rowFilter, limits, partitionKeys, clusteringIndexFilter);
    }


    /**
     * Creates a new read query on a single partition.
     *
     * @param metadata the table to query.
     * @param nowInSec the time in seconds to use are "now" for this query.
     * @param key the partition key for the partition to query.
     * @param columnFilter the column filter to use for the query.
     * @param filter the clustering index filter to use for the query.
     *
     * @return a newly created read query. The returned query will use no row filter and have no limits.
     */
    public static SinglePartitionReadQuery create(TableMetadata metadata,
                                                  int nowInSec,
                                                  DecoratedKey key,
                                                  ColumnFilter columnFilter,
                                                  ClusteringIndexFilter filter)
    {
        return create(metadata, nowInSec, columnFilter, RowFilter.NONE, DataLimits.NONE, key, filter);
    }

    /**
     * Creates a new read query on a single partition.
     *
     * @param metadata the table to query.
     * @param nowInSec the time in seconds to use are "now" for this query.
     * @param columnFilter the column filter to use for the query.
     * @param rowFilter the row filter to use for the query.
     * @param limits the limits to use for the query.
     * @param partitionKey the partition key for the partition to query.
     * @param clusteringIndexFilter the clustering index filter to use for the query.
     *
     * @return a newly created read query.
     */
    public static SinglePartitionReadQuery create(TableMetadata metadata,
                                                  int nowInSec,
                                                  ColumnFilter columnFilter,
                                                  RowFilter rowFilter,
                                                  DataLimits limits,
                                                  DecoratedKey partitionKey,
                                                  ClusteringIndexFilter clusteringIndexFilter)
    {
        return metadata.isVirtual()
             ? VirtualTableSinglePartitionReadQuery.create(metadata, nowInSec, columnFilter, rowFilter, limits, partitionKey, clusteringIndexFilter)
             : SinglePartitionReadCommand.create(metadata, nowInSec, columnFilter, rowFilter, limits, partitionKey, clusteringIndexFilter);
    }

    /**
     * Returns the key of the partition queried by this {@code ReadQuery}
     * @return the key of the partition queried
     */
    DecoratedKey partitionKey();

    /**
     * Creates a new {@code SinglePartitionReadQuery} with the specified limits.
     *
     * @param newLimits the new limits
     * @return the new {@code SinglePartitionReadQuery}
     */
    SinglePartitionReadQuery withUpdatedLimit(DataLimits newLimits);

    /**
     * Returns a new {@code SinglePartitionReadQuery} suitable to paging from the last returned row.
     *
     * @param lastReturned the last row returned by the previous page. The newly created query
     * will only query row that comes after this (in query order). This can be {@code null} if this
     * is the first page.
     * @param limits the limits to use for the page to query.
     *
     * @return the newly create query.
     */
    SinglePartitionReadQuery forPaging(Clustering lastReturned, DataLimits limits);

    @Override
    default SinglePartitionPager getPager(PagingState pagingState, ProtocolVersion protocolVersion)
    {
        return new SinglePartitionPager(this, pagingState, protocolVersion);
    }

    ClusteringIndexFilter clusteringIndexFilter();

    default boolean selectsKey(DecoratedKey key)
    {
        if (!this.partitionKey().equals(key))
            return false;

        return rowFilter().partitionKeyRestrictionsAreSatisfiedBy(key, metadata().partitionKeyType);
    }

    default boolean selectsClustering(DecoratedKey key, Clustering clustering)
    {
        if (clustering == Clustering.STATIC_CLUSTERING)
            return !columnFilter().fetchedColumns().statics.isEmpty();

        if (!clusteringIndexFilter().selects(clustering))
            return false;

        return rowFilter().clusteringKeyRestrictionsAreSatisfiedBy(clustering);
    }

    /**
     * Groups multiple single partition read queries.
     */
    abstract class Group implements ReadQuery
    {
        public final List queries;
        private final DataLimits limits;
        private final int nowInSec;
        private final boolean selectsFullPartitions;

        public Group(List queries, DataLimits limits)
        {
            assert !queries.isEmpty();
            this.queries = queries;
            this.limits = limits;
            T firstQuery = queries.get(0);
            this.nowInSec = firstQuery.nowInSec();
            this.selectsFullPartitions = firstQuery.selectsFullPartition();
            for (int i = 1; i < queries.size(); i++)
                assert queries.get(i).nowInSec() == nowInSec;
        }

        public int nowInSec()
        {
            return nowInSec;
        }

        public DataLimits limits()
        {
            return limits;
        }

        public TableMetadata metadata()
        {
            return queries.get(0).metadata();
        }

        @Override
        public boolean selectsFullPartition()
        {
            return selectsFullPartitions;
        }

        public ReadExecutionController executionController()
        {
            // Note that the only difference between the queries in a group must be the partition key on which
            // they applied. So as far as ReadOrderGroup is concerned, we can use any of the queries to start one.
            return queries.get(0).executionController();
        }

        public PartitionIterator executeInternal(ReadExecutionController controller)
        {
            // Note that the only difference between the queries in a group must be the partition key on which
            // they applied.
            boolean enforceStrictLiveness = queries.get(0).metadata().enforceStrictLiveness();
            return limits.filter(UnfilteredPartitionIterators.filter(executeLocally(controller, false), nowInSec),
                                 nowInSec,
                                 selectsFullPartitions,
                                 enforceStrictLiveness);
        }

        public UnfilteredPartitionIterator executeLocally(ReadExecutionController executionController)
        {
            return executeLocally(executionController, true);
        }

        /**
         * Implementation of {@link ReadQuery#executeLocally(ReadExecutionController)}.
         *
         * @param executionController - the {@code ReadExecutionController} protecting the read.
         * @param sort - whether to sort the inner queries by partition key, required for merging the iterator
         *               later on. This will be false when called by {@link ReadQuery#executeInternal(ReadExecutionController)}
         *               because in this case it is safe to do so as there is no merging involved and we don't want to
         *               change the old behavior which was to not sort by partition.
         *
         * @return - the iterator that can be used to retrieve the query result.
         */
        private UnfilteredPartitionIterator executeLocally(ReadExecutionController executionController, boolean sort)
        {
            List> partitions = new ArrayList<>(queries.size());
            for (T query : queries)
                partitions.add(Pair.of(query.partitionKey(), query.executeLocally(executionController)));

            if (sort)
                Collections.sort(partitions, (p1, p2) -> p1.getLeft().compareTo(p2.getLeft()));

            return UnfilteredPartitionIterators.concat(partitions.stream().map(p -> p.getRight()).collect(Collectors.toList()));
        }

        public QueryPager getPager(PagingState pagingState, ProtocolVersion protocolVersion)
        {
            if (queries.size() == 1)
                return new SinglePartitionPager(queries.get(0), pagingState, protocolVersion);

            return new MultiPartitionPager(this, pagingState, protocolVersion);
        }

        public boolean selectsKey(DecoratedKey key)
        {
            return Iterables.any(queries, c -> c.selectsKey(key));
        }

        public boolean selectsClustering(DecoratedKey key, Clustering clustering)
        {
            return Iterables.any(queries, c -> c.selectsClustering(key, clustering));
        }

        @Override
        public RowFilter rowFilter()
        {
            // Note that the only difference between the query in a group must be the partition key on which
            // they applied.
            return queries.get(0).rowFilter();
        }

        @Override
        public ColumnFilter columnFilter()
        {
            // Note that the only difference between the query in a group must be the partition key on which
            // they applied.
            return queries.get(0).columnFilter();
        }

        @Override
        public String toString()
        {
            return queries.toString();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy