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

com.pingcap.tikv.operation.iterator.ScanIterator Maven / Gradle / Ivy

There is a newer version: 3.2.3
Show newest version
/*
 * Copyright 2017 PingCAP, Inc.
 *
 * 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,
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.pingcap.tikv.operation.iterator;

import static java.util.Objects.requireNonNull;

import com.google.protobuf.ByteString;
import com.pingcap.tikv.TiConfiguration;
import com.pingcap.tikv.exception.GrpcException;
import com.pingcap.tikv.exception.TiClientInternalException;
import com.pingcap.tikv.key.Key;
import com.pingcap.tikv.region.RegionStoreClient.RegionStoreClientBuilder;
import com.pingcap.tikv.region.TiRegion;
import java.util.Iterator;
import java.util.List;
import org.tikv.kvproto.Kvrpcpb;

public abstract class ScanIterator implements Iterator {
  protected final TiConfiguration conf;
  protected final RegionStoreClientBuilder builder;
  protected List currentCache;
  protected ByteString startKey;
  protected int index = -1;
  protected int limit;
  protected boolean endOfScan = false;

  protected Key endKey;
  protected boolean hasEndKey;
  protected boolean processingLastBatch = false;

  ScanIterator(
      TiConfiguration conf,
      RegionStoreClientBuilder builder,
      ByteString startKey,
      ByteString endKey,
      int limit) {
    this.startKey = requireNonNull(startKey, "start key is null");
    this.endKey = Key.toRawKey(requireNonNull(endKey, "end key is null"));
    this.hasEndKey = !endKey.isEmpty();
    this.limit = limit;
    this.conf = conf;
    this.builder = builder;
  }

  /**
   * Load current region to cache, returns the region if loaded.
   *
   * @return TiRegion of current data loaded to cache
   * @throws GrpcException if scan still fails after backoff
   */
  abstract TiRegion loadCurrentRegionToCache() throws GrpcException;

  // return true if current cache is not loaded or empty
  boolean cacheLoadFails() {
    if (endOfScan || processingLastBatch) {
      return true;
    }
    if (startKey == null) {
      return true;
    }
    try {
      TiRegion region = loadCurrentRegionToCache();
      ByteString curRegionEndKey = region.getEndKey();
      // currentCache is null means no keys found, whereas currentCache is empty means no values
      // found. The difference lies in whether to continue scanning, because chances are that
      // an empty region exists due to deletion, region split, e.t.c.
      // See https://github.com/pingcap/tispark/issues/393 for details
      if (currentCache == null) {
        return true;
      }
      index = 0;
      Key lastKey;
      // Session should be single-threaded itself
      // so that we don't worry about conf change in the middle
      // of a transaction. Otherwise below code might lose data
      if (currentCache.size() < limit) {
        startKey = curRegionEndKey;
        lastKey = Key.toRawKey(curRegionEndKey);
      } else if (currentCache.size() > limit) {
        throw new IndexOutOfBoundsException(
            "current cache size = " + currentCache.size() + ", larger than " + limit);
      } else {
        // Start new scan from exact next key in current region
        lastKey = Key.toRawKey(currentCache.get(currentCache.size() - 1).getKey());
        startKey = lastKey.next().toByteString();
      }
      // notify last batch if lastKey is greater than or equal to endKey
      // if startKey is empty, it indicates +∞
      if (hasEndKey && lastKey.compareTo(endKey) >= 0 || startKey.isEmpty()) {
        processingLastBatch = true;
        startKey = null;
      }
    } catch (Exception e) {
      throw new TiClientInternalException("Error scanning data from region.", e);
    }
    return false;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy