private List<LineAndError> getLineAndError(BatchWriteRowResult result, List<OTSLine> lines) {
    List<LineAndError> errors = new ArrayList<LineAndError>();

    switch (conf.getOperation()) {
      case PUT_ROW:
        List<RowStatus> putStatus = result.getPutRowStatus(conf.getTableName());
        for (int i = 0; i < putStatus.size(); i++) {
          if (!putStatus.get(i).isSucceed()) {
            errors.add(new LineAndError(lines.get(i), putStatus.get(i).getError()));
          }
        }
        break;
      case UPDATE_ROW:
        List<RowStatus> updateStatus = result.getUpdateRowStatus(conf.getTableName());
        for (int i = 0; i < updateStatus.size(); i++) {
          if (!updateStatus.get(i).isSucceed()) {
            errors.add(new LineAndError(lines.get(i), updateStatus.get(i).getError()));
          }
        }
        break;
      default:
        throw new RuntimeException(
            String.format(OTSErrorMessage.OPERATION_PARSE_ERROR, conf.getOperation()));
    }
    return errors;
  }
  private void sendAll(List<OTSLine> lines) throws InterruptedException {
    Thread.sleep(Common.getDelaySendMillinSeconds(retryTimes, conf.getSleepInMilliSecond()));
    try {
      BatchWriteRowRequest batchWriteRowRequest = createRequset(lines);
      BatchWriteRowResult result =
          RetryHelper.executeWithRetry(
              new BatchWriteRowCallable(ots, batchWriteRowRequest),
              conf.getRetry(),
              conf.getSleepInMilliSecond());

      LOG.debug("Requst ID : {}", result.getRequestID());
      List<LineAndError> errors = getLineAndError(result, lines);
      if (!errors.isEmpty()) {
        if (retryTimes < conf.getRetry()) {
          retryTimes++;
          LOG.debug("Retry times : {}", retryTimes);
          List<OTSLine> newLines = new ArrayList<OTSLine>();
          for (LineAndError re : errors) {
            if (RetryHelper.canRetry(re.getError().getCode())) {
              RetryHelper.logManager.addException(re.getError(), result.getRequestID());
              newLines.add(re.getLine());
            } else {
              LOG.error("Can not retry, record row to collector. {}", re.getError().getMessage());
              collector.collectDirtyRecord(re.getLine().getRecord(), re.getError().getMessage());
            }
          }
          if (!newLines.isEmpty()) {
            sendAll(newLines);
          }
        } else {
          LOG.error("Retry times more than limition. RetryTime : {}", retryTimes);
          Common.collectDirtyRecord(collector, errors);
        }
      }
    } catch (Exception e) {
      LOG.debug("Send data fail.", e);
      if (isExceptionForSendOneByOne(e)) {
        if (lines.size() == 1) {
          LOG.error("Can not retry for Exception : {}", e.getMessage());
          Common.collectDirtyRecord(collector, lines, e.getMessage());
        } else {
          // 进入单行发送的分支
          sendAllOneByOne(lines);
        }
      } else {
        LOG.error("Can not send lines to OTS. {}", e.getMessage());
        Common.collectDirtyRecord(collector, lines, e.getMessage());
      }
    }
  }