public void incrementalRestoreTable(Connection conn, Path tableBackupPath, Path[] logDirs,
    TableName[] tableNames, TableName[] newTableNames, String incrBackupId,
    boolean keepOriginalSplits) throws IOException {
    try (Admin admin = conn.getAdmin()) {
      if (tableNames.length != newTableNames.length) {
        throw new IOException("Number of source tables and target tables does not match!");
      }
      FileSystem fileSys = tableBackupPath.getFileSystem(this.conf);

      // for incremental backup image, expect the table already created either by user or previous
      // full backup. Here, check that all new tables exists
      for (TableName tableName : newTableNames) {
        if (!admin.tableExists(tableName)) {
          throw new IOException("HBase table " + tableName
            + " does not exist. Create the table first, e.g. by restoring a full backup.");
        }
      }
      // adjust table schema
      for (int i = 0; i < tableNames.length; i++) {
        TableName tableName = tableNames[i];
        TableDescriptor tableDescriptor = getTableDescriptor(fileSys, tableName, incrBackupId);
        if (tableDescriptor == null) {
          throw new IOException("Can't find " + tableName + "'s descriptor.");
        }
        LOG.debug("Found descriptor " + tableDescriptor + " through " + incrBackupId);

        TableName newTableName = newTableNames[i];
        TableDescriptor newTableDescriptor = admin.getDescriptor(newTableName);
        List<ColumnFamilyDescriptor> families = Arrays.asList(tableDescriptor.getColumnFamilies());
        List<ColumnFamilyDescriptor> existingFamilies =
          Arrays.asList(newTableDescriptor.getColumnFamilies());
        TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(newTableDescriptor);
        boolean schemaChangeNeeded = false;
        for (ColumnFamilyDescriptor family : families) {
          if (!existingFamilies.contains(family)) {
            builder.setColumnFamily(family);
            schemaChangeNeeded = true;
          }
        }
        for (ColumnFamilyDescriptor family : existingFamilies) {
          if (!families.contains(family)) {
            builder.removeColumnFamily(family.getName());
            schemaChangeNeeded = true;
          }
        }
        if (schemaChangeNeeded) {
          modifyTableSync(conn, builder.build());
          LOG.info("Changed " + newTableDescriptor.getTableName() + " to: " + newTableDescriptor);
        }
      }
      configureForRestoreJob(keepOriginalSplits);
      RestoreJob restoreService = BackupRestoreFactory.getRestoreJob(conf);

      restoreService.run(logDirs, tableNames, restoreRootDir, newTableNames, false);
    }
  }
During incremental backup operation. Call WalPlayer to replay WAL in backup image Currently
tableNames and newTablesNames only contain single table, will be expanded to multiple tables in
the future
@param conn               HBase connection
@param tableBackupPath    backup path
@param logDirs            : incremental backup folders, which contains WAL
@param tableNames         : source tableNames(table names were backuped)
@param newTableNames      : target tableNames(table names to be restored to)
@param incrBackupId       incremental backup Id
@param keepOriginalSplits whether the original region splits from the full backup should be
                          kept
@throws IOException exception
hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/util/RestoreTool.java