@Override
  public boolean next() {
    readBuffer.clear();
    searchRow = null;
    row = null;
    index++;
    if (result != null && index < result.length) {
      setSearchRow();
      return true;
    }

    Transaction transaction = session.getTransaction();
    List<KeyValue> kvs;
    KeyValue kv;
    Result r;
    long queryTimestamp;
    try {
      result = session.getRegionServer().next(scannerId, fetchSize);
      ArrayList<Result> list = new ArrayList<Result>(result.length);
      for (int i = 0; i < result.length; i++) {
        r = result[i];
        kvs = r.list();
        // 当Result.isEmpty=true时,r.list()也返回null,所以这里不用再判断kvs.isEmpty
        if (kvs != null) {
          kv = kvs.get(0);
          queryTimestamp = kv.getTimestamp();
          if (queryTimestamp < transaction.getStartTimestamp() & queryTimestamp % 2 == 0) {
            if (kv.getValueLength() != 0) // kv已删除,不需要再处理
            list.add(r);
            continue;
          }
        }

        // TODO Filter.filter很慢
        r = new Result(Filter.filter(session.getRegionServer(), regionName, transaction, kvs, 1));
        if (!r.isEmpty()) list.add(r);
      }

      result = list.toArray(new Result[0]);
    } catch (Exception e) {
      close();
      throw DbException.convert(e);
    }

    index = 0;

    if (result != null && result.length > 0) {
      setSearchRow();
      return true;
    }

    close();
    return false;
  }
 private void close() {
   try {
     session.getRegionServer().close(scannerId);
   } catch (IOException e) {
     // ignore
   }
 }
  public HBaseSecondaryIndexCursor(
      HBaseSecondaryIndex index, TableFilter filter, byte[] startKey, byte[] endKey) {
    defaultColumnFamilyName =
        Bytes.toBytes(((HBaseTable) filter.getTable()).getDefaultColumnFamilyName());
    secondaryIndex = index;
    session = (HBaseSession) filter.getSession();
    Prepared p = filter.getPrepared();
    if (p instanceof WithWhereClause) {
      regionName = Bytes.toBytes(((WithWhereClause) p).getWhereClauseSupport().getRegionName());
    }

    if (regionName == null) throw new RuntimeException("regionName is null");

    fetchSize = filter.getPrepared().getFetchSize();
    // 非查询的操作一般不设置fetchSize,此时fetchSize为0,所以要设置一个默认值
    // if (fetchSize < 1 && !filter.getPrepared().isQuery())
    if (fetchSize < 1) fetchSize = SysProperties.SERVER_RESULT_SET_FETCH_SIZE;

    if (filter.getSelect() != null) columns = filter.getSelect().getColumns(filter);
    else columns = Arrays.asList(filter.getTable().getColumns());

    if (startKey == null) startKey = HConstants.EMPTY_BYTE_ARRAY;
    if (endKey == null) endKey = HConstants.EMPTY_BYTE_ARRAY;

    Scan scan = new Scan();
    scan.setMaxVersions(1);
    try {
      HRegionInfo info = session.getRegionServer().getRegionInfo(regionName);
      if (Bytes.compareTo(startKey, info.getStartKey()) >= 0) scan.setStartRow(startKey);
      else scan.setStartRow(info.getStartKey());

      if (Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY)) scan.setStopRow(info.getEndKey());
      else if (Bytes.compareTo(endKey, info.getEndKey()) < 0) scan.setStopRow(endKey);
      else scan.setStopRow(info.getEndKey());

      scan.addColumn(HBaseSecondaryIndex.PSEUDO_FAMILY, HBaseSecondaryIndex.PSEUDO_COLUMN);

      scannerId = session.getRegionServer().openScanner(regionName, scan);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }