/** * 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.secindex; import java.nio.ByteBuffer; import java.util.*; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.db.*; import org.apache.cassandra.db.filter.*; import org.apache.cassandra.dht.AbstractBounds; import org.apache.cassandra.io.sstable.SSTableReader; import org.apache.cassandra.thrift.IndexExpression; import org.apache.cassandra.thrift.IndexOperator; import org.apache.cassandra.thrift.IndexType; import org.apache.cassandra.utils.CloseableIterator; /** * Abstract base class for different types of secondary indexes. */ public abstract class SecondaryIndex { public final ColumnDefinition cdef; public SecondaryIndex(ColumnDefinition cdef) { this.cdef = cdef; } public static SecondaryIndex open(ColumnDefinition info, ColumnFamilyStore cfs) { SecondaryIndex idx; if (info.getIndexType() == IndexType.KEYS) idx = new KeysIndex(info, cfs); else { assert info.getIndexType() == IndexType.KEYS_BITMAP; idx = new KeysBitmapIndex(info, cfs); } idx.initialize(); return idx; } /** * Called after construction: default impl is a noop. */ public void initialize() {} /** * Called when this index is no longer necessary, and persisted data should be * removed from disk. */ public abstract void purge(); /** * @return The fraction of rows matched by the given expression for this index, or * Double.MAX_VALUE if this index cannot be used. */ public abstract double selectivity(IndexExpression expr); /** * @return True if keys returned by an iterator for the given expression are certain matches, * as opposed to probable matches. */ public abstract boolean certainty(IndexExpression expr); /** * @return An iterator over keys that match the given expression with certainty(). */ public abstract CloseableIterator<DecoratedKey> iterator(AbstractBounds range, IndexExpression expr, ByteBuffer startKey); /** * Leaky abstraction. * @return The private ColumnFamilyStore storing this index, or null. */ public abstract ColumnFamilyStore getIndexCFS(); public static boolean satisfies(ColumnFamily data, List<IndexExpression> expressions) { for (IndexExpression expression : expressions) { // check column data vs expression IColumn column = data.getColumn(expression.column_name); if (column == null) return false; int v = data.getComparator().compare(column.value(), expression.value); if (!satisfies(v, expression.op)) return false; } return true; } static boolean satisfies(int comparison, IndexOperator op) { switch (op) { case EQ: return comparison == 0; case GTE: return comparison >= 0; case GT: return comparison > 0; case LTE: return comparison <= 0; case LT: return comparison < 0; default: throw new IllegalStateException(); } } }