/* * * * 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.usergrid.persistence.graph.serialization.impl.shard.impl; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.usergrid.persistence.core.scope.ApplicationScope; import org.apache.usergrid.persistence.graph.MarkedEdge; import org.apache.usergrid.persistence.graph.serialization.impl.shard.DirectedEdgeMeta; import org.apache.usergrid.persistence.graph.serialization.impl.shard.Shard; import org.apache.usergrid.persistence.graph.serialization.impl.shard.ShardEntryGroup; import org.apache.usergrid.persistence.graph.serialization.impl.shard.ShardGroupDeletion; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; /** * Iterator to keep iterating over multiple shard groups to stream results * * @param <T> The parsed return type */ public abstract class ShardGroupColumnIterator implements Iterator<MarkedEdge> { private static final Logger logger = LoggerFactory.getLogger( ShardGroupColumnIterator.class ); private final ApplicationScope applicationScope; private final DirectedEdgeMeta directedEdgeMeta; private final ShardGroupDeletion shardGroupDeletion; private final Iterator<ShardEntryGroup> entryGroupIterator; private Iterator<MarkedEdge> elements; public ShardGroupColumnIterator( final ApplicationScope applicationScope, final DirectedEdgeMeta directedEdgeMeta, final ShardGroupDeletion shardGroupDeletion, final Iterator<ShardEntryGroup> entryGroupIterator ) { this.applicationScope = applicationScope; this.directedEdgeMeta = directedEdgeMeta; this.shardGroupDeletion = shardGroupDeletion; this.entryGroupIterator = entryGroupIterator; } @Override public boolean hasNext() { if ( elements == null ) { return advance(); } if ( elements.hasNext() ) { return true; } //we've exhausted our shard groups and we don't have a next, we can't continue if ( !entryGroupIterator.hasNext() ) { return false; } return advance(); } @Override public MarkedEdge next() { if ( !hasNext() ) { throw new NoSuchElementException( "There are no more rows or columns left to advance" ); } return elements.next(); } @Override public void remove() { throw new UnsupportedOperationException( "Remove is unsupported" ); } /** * Get an iterator for the shard entry group * * @param readShards the read shards to use */ protected abstract Iterator<MarkedEdge> getIterator( Collection<Shard> readShards ); protected abstract Iterator<MarkedEdge> getIteratorFullRange( Collection<Shard> readShards ); public boolean advance() { if (logger.isTraceEnabled()) logger.trace( "Advancing from shard entry group iterator" ); while ( entryGroupIterator.hasNext() ) { final ShardEntryGroup group = entryGroupIterator.next(); if (logger.isTraceEnabled()) logger.trace( "Shard entry group is {}. Searching for edges in the shard", group ); elements = getIterator( group.getReadShards() ); /** * We're done, we have some columns to return */ if ( elements.hasNext() ) { if (logger.isTraceEnabled()) logger.trace( "Found edges in shard entry group {}", group ); return true; } else { if (logger.isTraceEnabled()) logger.trace( "Our shard is empty, we need to perform an audit on shard group {}", group ); //fire and forget if we miss it here, we'll get it next read shardGroupDeletion.maybeDeleteShard(this.applicationScope, this.directedEdgeMeta, group, getIteratorFullRange( group.getReadShards() ) ); } } if (logger.isTraceEnabled()) logger.trace( "Completed iterating shard group iterator" ); return false; } }