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

org.apache.cassandra.cql3.restrictions.TokenFilter Maven / Gradle / Ivy

There is a newer version: 4.3.1.0
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.cql3.restrictions;

import java.nio.ByteBuffer;
import java.util.*;

import com.google.common.collect.BoundType;
import com.google.common.collect.ImmutableRangeSet;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;

import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.statements.Bound;
import org.apache.cassandra.db.filter.RowFilter;
import org.apache.cassandra.dht.IPartitioner;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.index.SecondaryIndexManager;

import static org.apache.cassandra.cql3.statements.Bound.END;
import static org.apache.cassandra.cql3.statements.Bound.START;

/**
 * Restriction decorator used to merge non-token restriction and token restriction on partition keys.
 *
 * 

If all partition key columns have non-token restrictions and do not need filtering, they take precedence * when calculating bounds, incusiveness etc (see CASSANDRA-12149).

*/ final class TokenFilter implements PartitionKeyRestrictions { /** * The decorated restriction */ private final PartitionKeyRestrictions restrictions; /** * The restriction on the token */ private final TokenRestriction tokenRestriction; /** * Partitioner to manage tokens, extracted from tokenRestriction metadata. */ private final IPartitioner partitioner; public boolean hasIN() { return isOnToken() ? false : restrictions.hasIN(); } public boolean hasContains() { return isOnToken() ? false : restrictions.hasContains(); } public boolean hasOnlyEqualityRestrictions() { return isOnToken() ? false : restrictions.hasOnlyEqualityRestrictions(); } @Override public Set getRestrictions(ColumnDefinition columnDef) { Set set = new HashSet<>(); set.addAll(restrictions.getRestrictions(columnDef)); set.addAll(tokenRestriction.getRestrictions(columnDef)); return set; } @Override public boolean isOnToken() { // if all partition key columns have non-token restrictions and do not need filtering, // we can simply use the token range to filter those restrictions and then ignore the token range return needFiltering(tokenRestriction.metadata) || restrictions.size() < tokenRestriction.size(); } public TokenFilter(PartitionKeyRestrictions restrictions, TokenRestriction tokenRestriction) { this.restrictions = restrictions; this.tokenRestriction = tokenRestriction; this.partitioner = tokenRestriction.metadata.partitioner; } @Override public List values(QueryOptions options) throws InvalidRequestException { return filter(restrictions.values(options), options); } @Override public PartitionKeyRestrictions mergeWith(Restriction restriction) throws InvalidRequestException { if (restriction.isOnToken()) return new TokenFilter(restrictions, (TokenRestriction) tokenRestriction.mergeWith(restriction)); return new TokenFilter(restrictions.mergeWith(restriction), tokenRestriction); } @Override public boolean isInclusive(Bound bound) { return isOnToken() ? tokenRestriction.isInclusive(bound) : restrictions.isInclusive(bound); } @Override public boolean hasBound(Bound bound) { return isOnToken() ? tokenRestriction.hasBound(bound) : restrictions.hasBound(bound); } @Override public List bounds(Bound bound, QueryOptions options) throws InvalidRequestException { return isOnToken() ? tokenRestriction.bounds(bound, options) : restrictions.bounds(bound, options); } /** * Filter the values returned by the restriction. * * @param values the values returned by the decorated restriction * @param options the query options * @return the values matching the token restriction * @throws InvalidRequestException if the request is invalid */ private List filter(List values, QueryOptions options) throws InvalidRequestException { RangeSet rangeSet = tokenRestriction.hasSlice() ? toRangeSet(tokenRestriction, options) : toRangeSet(tokenRestriction.values(options)); return filterWithRangeSet(rangeSet, values); } /** * Filter out the values for which the tokens are not included within the specified range. * * @param tokens the tokens range * @param values the restricted values * @return the values for which the tokens are not included within the specified range. */ private List filterWithRangeSet(RangeSet tokens, List values) { List remaining = new ArrayList<>(); for (ByteBuffer value : values) { Token token = partitioner.getToken(value); if (!tokens.contains(token)) continue; remaining.add(value); } return remaining; } /** * Converts the specified list into a range set. * * @param buffers the token restriction values * @return the range set corresponding to the specified list */ private RangeSet toRangeSet(List buffers) { ImmutableRangeSet.Builder builder = ImmutableRangeSet.builder(); for (ByteBuffer buffer : buffers) builder.add(Range.singleton(deserializeToken(buffer))); return builder.build(); } /** * Converts the specified slice into a range set. * * @param slice the slice to convert * @param options the query option * @return the range set corresponding to the specified slice * @throws InvalidRequestException if the request is invalid */ private RangeSet toRangeSet(TokenRestriction slice, QueryOptions options) throws InvalidRequestException { if (slice.hasBound(START)) { Token start = deserializeToken(slice.bounds(START, options).get(0)); BoundType startBoundType = toBoundType(slice.isInclusive(START)); if (slice.hasBound(END)) { BoundType endBoundType = toBoundType(slice.isInclusive(END)); Token end = deserializeToken(slice.bounds(END, options).get(0)); if (start.equals(end) && (BoundType.OPEN == startBoundType || BoundType.OPEN == endBoundType)) return ImmutableRangeSet.of(); if (start.compareTo(end) <= 0) return ImmutableRangeSet.of(Range.range(start, startBoundType, end, endBoundType)); return ImmutableRangeSet. builder() .add(Range.upTo(end, endBoundType)) .add(Range.downTo(start, startBoundType)) .build(); } return ImmutableRangeSet.of(Range.downTo(start, startBoundType)); } Token end = deserializeToken(slice.bounds(END, options).get(0)); return ImmutableRangeSet.of(Range.upTo(end, toBoundType(slice.isInclusive(END)))); } /** * Deserializes the token corresponding to the specified buffer. * * @param buffer the buffer * @return the token corresponding to the specified buffer */ private Token deserializeToken(ByteBuffer buffer) { return partitioner.getTokenFactory().fromByteArray(buffer); } private static BoundType toBoundType(boolean inclusive) { return inclusive ? BoundType.CLOSED : BoundType.OPEN; } @Override public ColumnDefinition getFirstColumn() { return restrictions.getFirstColumn(); } @Override public ColumnDefinition getLastColumn() { return restrictions.getLastColumn(); } @Override public List getColumnDefs() { return restrictions.getColumnDefs(); } @Override public void addFunctionsTo(List functions) { restrictions.addFunctionsTo(functions); } @Override public boolean hasSupportingIndex(SecondaryIndexManager indexManager) { return restrictions.hasSupportingIndex(indexManager); } @Override public void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, QueryOptions options) { restrictions.addRowFilterTo(filter, indexManager, options); } @Override public boolean isEmpty() { return restrictions.isEmpty(); } @Override public int size() { return restrictions.size(); } @Override public boolean needFiltering(CFMetaData cfm) { return restrictions.needFiltering(cfm); } @Override public boolean hasUnrestrictedPartitionKeyComponents(CFMetaData cfm) { return restrictions.hasUnrestrictedPartitionKeyComponents(cfm); } @Override public boolean hasSlice() { return restrictions.hasSlice(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy