Package com.googlecode.objectify.impl

Source Code of com.googlecode.objectify.impl.ChunkingIterator

package com.googlecode.objectify.impl;

import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Index;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.QueryResultIterator;
import com.google.common.collect.Iterators;
import com.google.common.collect.PeekingIterator;
import com.googlecode.objectify.Key;

import java.util.List;
import java.util.NoSuchElementException;
import java.util.logging.Logger;

/**
* Base class for normal and hybrid iterators, handles the chunking logic.
*
* The bulk of the complexity is in the QueryResultStreamIterator; this just handles stripping out
* null values but being careful about preserving cursor behavior.
*/
public class ChunkingIterator<T> implements QueryResultIterator<T> {
  /** */
  static final Logger log = Logger.getLogger(ChunkingIterator.class.getName());

  /** Input values */
  private PreparedQuery pq;
  private QueryResultIterator<Key<T>> source;

  /** As we process */
  private PeekingIterator<ResultWithCursor<T>> stream;

  /** Track the values for the next time we need to get this */
  private Cursor nextCursor;
  private int nextOffset;

  /** */
  public ChunkingIterator(LoadEngine loadEngine, PreparedQuery pq, QueryResultIterator<Key<T>> source, int chunkSize) {
    this.pq = pq;
    this.source = source;

    ChunkIterator<T> chunkIt = new ChunkIterator<>(source, chunkSize, loadEngine);
    this.stream = Iterators.peekingIterator(Iterators.concat(chunkIt));

    // Always start with a cursor; there might actually be any results
    this.nextCursor = source.getCursor();
  }

  @Override
  public boolean hasNext() {
    while (stream.hasNext()) {
      ResultWithCursor<T> peek = stream.peek();
      nextCursor = peek.getCursor();
      nextOffset = peek.getOffset();

      if (peek.getResult() != null)
        return true;
      else
        stream.next();
    }

    return false;
  }

  @Override
  public T next() {
    while (stream.hasNext()) {
      ResultWithCursor<T> rc = stream.next();

      if (rc.isLast()) {
        // We know we are back to the beginning of a batch, and the source cursor should be pointed the right place.
        nextCursor = source.getCursor();
        nextOffset = 0;
      } else {
        nextCursor = rc.getCursor();
        nextOffset = rc.getOffset() + 1;
      }

      if (rc.getResult() != null) {
        return rc.getResult();
      }
    }

    throw new NoSuchElementException();
  }

  /** Not implemented */
  @Override
  public void remove() {
    throw new UnsupportedOperationException();
  }

  /**
   * From Alfred Fuller (principal GAE datastore guru):
   *
   * Calling getCursor() for results in the middle of a batch forces the sdk to run a new query as seen here:
   * http://code.google.com/p/googleappengine/source/browse/trunk/java/src/main/com/google/appengine/api/datastore/Cursor.java#70
   *
   * Doing this for every result will definitely give you really bad performance. I have several yet to be implemented ideas
   * that would solve this problem (which you potentially could push me into prioritizing), but I believe you can solve the
   * performance problem today by saving the start_cursor an offset into the batch. Then you can evaluate the real cursor on
   * demand using "query.asQueryResultIterator(withStartCursor(cursor).offset(n).limit(0)).getCursor()"
   */
  @Override
  public Cursor getCursor() {
    if (nextOffset == 0) {
      return nextCursor;
    } else {
      // There may not be a baseCursor if we haven't iterated yet
      FetchOptions opts = FetchOptions.Builder.withDefaults();
      if (nextCursor != null)
        opts = opts.startCursor(nextCursor);

      return pq.asQueryResultIterator(opts.offset(nextOffset).limit(0)).getCursor();
    }
  }

  @Override
  public List<Index> getIndexList() {
    return this.source.getIndexList();
  }
}
TOP

Related Classes of com.googlecode.objectify.impl.ChunkingIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.