Search in sources :

Example 6 with IndexExpression

use of org.apache.cassandra.thrift.IndexExpression in project eiger by wlloyd.

the class RangeSliceCommandSerializer method serialize.

public void serialize(RangeSliceCommand sliceCommand, DataOutput dos, int version) throws IOException {
    dos.writeUTF(sliceCommand.keyspace);
    dos.writeUTF(sliceCommand.column_family);
    ByteBuffer sc = sliceCommand.super_column;
    dos.writeInt(sc == null ? 0 : sc.remaining());
    if (sc != null)
        ByteBufferUtil.write(sc, dos);
    TSerializer ser = new TSerializer(new TBinaryProtocol.Factory());
    FBUtilities.serialize(ser, sliceCommand.predicate, dos);
    if (version >= MessagingService.VERSION_11) {
        if (sliceCommand.row_filter == null) {
            dos.writeInt(0);
        } else {
            dos.writeInt(sliceCommand.row_filter.size());
            for (IndexExpression expr : sliceCommand.row_filter) FBUtilities.serialize(ser, expr, dos);
        }
    }
    AbstractBounds.serializer().serialize(sliceCommand.range, dos, version);
    dos.writeInt(sliceCommand.maxResults);
    if (version >= MessagingService.VERSION_11) {
        dos.writeBoolean(sliceCommand.maxIsColumns);
    }
}
Also used : TSerializer(org.apache.thrift.TSerializer) TBinaryProtocol(org.apache.cassandra.thrift.TBinaryProtocol) IndexExpression(org.apache.cassandra.thrift.IndexExpression) ByteBuffer(java.nio.ByteBuffer)

Example 7 with IndexExpression

use of org.apache.cassandra.thrift.IndexExpression in project eiger by wlloyd.

the class SecondaryIndexManager method getIndexSearchersForQuery.

/**
     * Get a list of IndexSearchers from the union of expression index types
     * @param clause the query clause
     * @return the searchers needed to query the index
     */
private List<SecondaryIndexSearcher> getIndexSearchersForQuery(List<IndexExpression> clause) {
    List<SecondaryIndexSearcher> indexSearchers = new ArrayList<SecondaryIndexSearcher>();
    Map<String, Set<ByteBuffer>> groupByIndexType = new HashMap<String, Set<ByteBuffer>>();
    //Group columns by type
    for (IndexExpression ix : clause) {
        SecondaryIndex index = getIndexForColumn(ix.column_name);
        if (index == null)
            continue;
        Set<ByteBuffer> columns = groupByIndexType.get(index.getClass().getCanonicalName());
        if (columns == null) {
            columns = new HashSet<ByteBuffer>();
            groupByIndexType.put(index.getClass().getCanonicalName(), columns);
        }
        columns.add(ix.column_name);
    }
    //create searcher per type
    for (Map.Entry<String, Set<ByteBuffer>> entry : groupByIndexType.entrySet()) {
        indexSearchers.add(getIndexForColumn(entry.getValue().iterator().next()).createSecondaryIndexSearcher(entry.getValue()));
    }
    return indexSearchers;
}
Also used : IndexExpression(org.apache.cassandra.thrift.IndexExpression) ByteBuffer(java.nio.ByteBuffer)

Example 8 with IndexExpression

use of org.apache.cassandra.thrift.IndexExpression in project eiger by wlloyd.

the class KeysSearcher method getIndexedIterator.

public ColumnFamilyStore.AbstractScanIterator getIndexedIterator(final AbstractBounds<RowPosition> range, final ExtendedFilter filter) {
    // Start with the most-restrictive indexed clause, then apply remaining clauses
    // to each row matching that clause.
    // TODO: allow merge join instead of just one index + loop
    final IndexExpression primary = highestSelectivityPredicate(filter.getClause());
    final SecondaryIndex index = indexManager.getIndexForColumn(primary.column_name);
    if (logger.isDebugEnabled())
        logger.debug("Primary scan clause is " + baseCfs.getComparator().getString(primary.column_name));
    assert index != null;
    final DecoratedKey indexKey = indexManager.getIndexKeyFor(primary.column_name, primary.value);
    /*
         * XXX: If the range requested is a token range, we'll have to start at the beginning (and stop at the end) of
         * the indexed row unfortunately (which will be inefficient), because we have not way to intuit the small
         * possible key having a given token. A fix would be to actually store the token along the key in the
         * indexed row.
         */
    final ByteBuffer startKey = range.left instanceof DecoratedKey ? ((DecoratedKey) range.left).key : ByteBufferUtil.EMPTY_BYTE_BUFFER;
    final ByteBuffer endKey = range.right instanceof DecoratedKey ? ((DecoratedKey) range.right).key : ByteBufferUtil.EMPTY_BYTE_BUFFER;
    return new ColumnFamilyStore.AbstractScanIterator() {

        private ByteBuffer lastSeenKey = startKey;

        private Iterator<IColumn> indexColumns;

        private final QueryPath path = new QueryPath(baseCfs.columnFamily);

        private int columnsRead = Integer.MAX_VALUE;

        protected Row computeNext() {
            int meanColumns = Math.max(index.getIndexCfs().getMeanColumns(), 1);
            // We shouldn't fetch only 1 row as this provides buggy paging in case the first row doesn't satisfy all clauses
            int rowsPerQuery = Math.max(Math.min(filter.maxRows(), filter.maxColumns() / meanColumns), 2);
            while (true) {
                if (indexColumns == null || !indexColumns.hasNext()) {
                    if (columnsRead < rowsPerQuery) {
                        logger.debug("Read only {} (< {}) last page through, must be done", columnsRead, rowsPerQuery);
                        return endOfData();
                    }
                    if (logger.isDebugEnabled())
                        logger.debug(String.format("Scanning index %s starting with %s", expressionString(primary), index.getBaseCfs().metadata.getKeyValidator().getString(startKey)));
                    QueryFilter indexFilter = QueryFilter.getSliceFilter(indexKey, new QueryPath(index.getIndexCfs().getColumnFamilyName()), lastSeenKey, endKey, false, rowsPerQuery);
                    ColumnFamily indexRow = index.getIndexCfs().getColumnFamily(indexFilter);
                    logger.debug("fetched {}", indexRow);
                    if (indexRow == null) {
                        logger.debug("no data, all done");
                        return endOfData();
                    }
                    Collection<IColumn> sortedColumns = indexRow.getSortedColumns();
                    columnsRead = sortedColumns.size();
                    indexColumns = sortedColumns.iterator();
                    IColumn firstColumn = sortedColumns.iterator().next();
                    // Paging is racy, so it is possible the first column of a page is not the last seen one.
                    if (lastSeenKey != startKey && lastSeenKey.equals(firstColumn.name())) {
                        // skip the row we already saw w/ the last page of results
                        indexColumns.next();
                        columnsRead--;
                        logger.debug("Skipping {}", baseCfs.getComparator().getString(firstColumn.name()));
                    } else if (range instanceof Range && indexColumns.hasNext() && firstColumn.equals(startKey)) {
                        // skip key excluded by range
                        indexColumns.next();
                        columnsRead--;
                        logger.debug("Skipping first key as range excludes it");
                    }
                }
                while (indexColumns.hasNext()) {
                    IColumn column = indexColumns.next();
                    lastSeenKey = column.name();
                    if (column.isMarkedForDelete()) {
                        logger.debug("skipping {}", column.name());
                        continue;
                    }
                    DecoratedKey dk = baseCfs.partitioner.decorateKey(lastSeenKey);
                    if (!range.right.isMinimum(baseCfs.partitioner) && range.right.compareTo(dk) < 0) {
                        logger.debug("Reached end of assigned scan range");
                        return endOfData();
                    }
                    if (!range.contains(dk)) {
                        logger.debug("Skipping entry {} outside of assigned scan range", dk.token);
                        continue;
                    }
                    logger.debug("Returning index hit for {}", dk);
                    ColumnFamily data = baseCfs.getColumnFamily(new QueryFilter(dk, path, filter.initialFilter()));
                    // While the column family we'll get in the end should contains the primary clause column, the initialFilter may not have found it and can thus be null
                    if (data == null)
                        data = ColumnFamily.create(baseCfs.metadata);
                    return new Row(dk, data);
                }
            }
        }

        public void close() throws IOException {
        }
    };
}
Also used : IndexExpression(org.apache.cassandra.thrift.IndexExpression) Range(org.apache.cassandra.dht.Range) ByteBuffer(java.nio.ByteBuffer) SecondaryIndex(org.apache.cassandra.db.index.SecondaryIndex) IColumnIterator(org.apache.cassandra.db.columniterator.IColumnIterator)

Aggregations

IndexExpression (org.apache.cassandra.thrift.IndexExpression)8 ByteBuffer (java.nio.ByteBuffer)4 IdentityQueryFilter (org.apache.cassandra.db.columniterator.IdentityQueryFilter)3 SecondaryIndex (org.apache.cassandra.db.index.SecondaryIndex)3 IPartitioner (org.apache.cassandra.dht.IPartitioner)3 IFilter (org.apache.cassandra.db.filter.IFilter)2 TBinaryProtocol (org.apache.cassandra.thrift.TBinaryProtocol)2 Test (org.junit.Test)2 IColumnIterator (org.apache.cassandra.db.columniterator.IColumnIterator)1 BytesToken (org.apache.cassandra.dht.BytesToken)1 Range (org.apache.cassandra.dht.Range)1 TokenMetadata (org.apache.cassandra.locator.TokenMetadata)1 SlicePredicate (org.apache.cassandra.thrift.SlicePredicate)1 NodeId (org.apache.cassandra.utils.NodeId)1 TDeserializer (org.apache.thrift.TDeserializer)1 TSerializer (org.apache.thrift.TSerializer)1