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

com.netflix.astyanax.thrift.ThriftAllRowsImpl Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright 2011 Netflix
 * 
 * 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.netflix.astyanax.thrift;

import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.cassandra.thrift.KeyRange;
import org.apache.cassandra.thrift.KeySlice;
import org.apache.commons.lang.NotImplementedException;

import com.google.common.collect.Iterables;
import com.netflix.astyanax.model.ColumnFamily;
import com.netflix.astyanax.model.Row;
import com.netflix.astyanax.model.Rows;
import com.netflix.astyanax.partitioner.Partitioner;
import com.netflix.astyanax.thrift.model.ThriftColumnOrSuperColumnListImpl;
import com.netflix.astyanax.thrift.model.ThriftRowImpl;

public class ThriftAllRowsImpl implements Rows {
    private ColumnFamily columnFamily;
    private ThriftAllRowsQueryImpl query;
    private final Partitioner partitioner;

    public ThriftAllRowsImpl(Partitioner partitioner, ThriftAllRowsQueryImpl query, ColumnFamily columnFamily) {
        this.columnFamily = columnFamily;
        this.query        = query;
        this.partitioner  = partitioner;
    }

    /**
     * Each call to .iterator() returns a new context starting at the beginning
     * of the column family.
     */
    @Override
    public Iterator> iterator() {
        return new Iterator>() {
            private KeyRange range;
            private org.apache.cassandra.thrift.KeySlice lastRow;
            private List list = null;
            private Iterator iter = null;
            private boolean bContinueSearch = true;
            private boolean bIgnoreTombstones = true;

            {
	            String startToken = query.getStartToken() == null ? partitioner.getMinToken() : query.getStartToken();
	            String endToken = query.getEndToken() == null ? partitioner.getMaxToken() : query.getEndToken();

                range = new KeyRange()
                        .setCount(query.getBlockSize())
                        .setStart_token(startToken)
                        .setEnd_token(endToken);
                
                if (query.getIncludeEmptyRows() == null) {
                    if (query.getPredicate().isSetSlice_range() && query.getPredicate().getSlice_range().getCount() == 0) {
                        bIgnoreTombstones = false;
                    }
                }
                else {
                    bIgnoreTombstones = !query.getIncludeEmptyRows();
                }
            }

            @Override
            public boolean hasNext() {
                // Get the next block
                while (iter == null || (!iter.hasNext() && bContinueSearch)) {
                    if (lastRow != null) {
                        // Determine the start token for the next page
                        String token = partitioner.getTokenForKey(ByteBuffer.wrap(lastRow.getKey()));
                        if (query.getRepeatLastToken()) {
                            // Start token is non-inclusive
                            range.setStart_token(partitioner.getTokenMinusOne(token));
                        }
                        else {
                            range.setStart_token(token);
                        }
                    }

                    // Get the next block of rows from cassandra, exit if none returned
                    list = query.getNextBlock(range);
                    if (list == null || list.isEmpty()) {
                        return false;
                    }
                    
                    // Since we may trim tombstones set a flag indicating whether a complete
                    // block was returned so we can know to try to fetch the next one
                    bContinueSearch = (list.size() == query.getBlockSize());

                    // Trim the list from tombstoned rows, i.e. rows with no columns
                    iter = list.iterator();
                    if (iter == null || !iter.hasNext()) {
                        return false;
                    }

                    KeySlice previousLastRow = lastRow;
                    lastRow = Iterables.getLast(list);
                    
                    if (query.getRepeatLastToken() && previousLastRow != null) {
                        iter.next();
                        iter.remove();
                    }
                    
                    if (iter.hasNext() && bIgnoreTombstones) {
                        // Discard any tombstones
                        while (iter.hasNext()) {
                            KeySlice row = iter.next();
                            if (row.getColumns().isEmpty()) {
                                iter.remove();
                            }
                        }
                        
                        // Get the iterator again
                        iter = list.iterator();
                    }
                }
                return iter.hasNext();
            }

            @Override
            public Row next() {
                org.apache.cassandra.thrift.KeySlice row = iter.next();
                return new ThriftRowImpl(columnFamily.getKeySerializer().fromBytes(row.getKey()),
                        ByteBuffer.wrap(row.getKey()), new ThriftColumnOrSuperColumnListImpl(row.getColumns(),
                                columnFamily.getColumnSerializer()));
            }

            @Override
            public void remove() {
                throw new IllegalStateException();
            }
        };
    }

    @Override
    public Row getRow(K key) {
        throw new NotImplementedException("Only iterator based access is implemented");
    }

    @Override
    public int size() {
        throw new NotImplementedException("Only iterator based access is implemented");
    }

    @Override
    public boolean isEmpty() {
        throw new NotImplementedException("Only iterator based access is implemented");
    }

    @Override
    public Row getRowByIndex(int i) {
        throw new NotImplementedException("Only iterator based access is implemented");
    }

    @Override
    public Collection getKeys() {
        throw new NotImplementedException("Only iterator based access is implemented");
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy