You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by gi...@apache.org on 2018/12/27 14:53:55 UTC

[49/51] [partial] hbase-site git commit: Published site at 7820ba1dbdba58b1002cdfde08eb21aa7a0bb6da.

http://git-wip-us.apache.org/repos/asf/hbase-site/blob/09ea0d5f/apidocs/org/apache/hadoop/hbase/mapreduce/CopyTable.html
----------------------------------------------------------------------
diff --git a/apidocs/org/apache/hadoop/hbase/mapreduce/CopyTable.html b/apidocs/org/apache/hadoop/hbase/mapreduce/CopyTable.html
index bc9720d..56ae45a 100644
--- a/apidocs/org/apache/hadoop/hbase/mapreduce/CopyTable.html
+++ b/apidocs/org/apache/hadoop/hbase/mapreduce/CopyTable.html
@@ -119,7 +119,7 @@ var activeTableTab = "activeTableTab";
 <hr>
 <br>
 <pre>@InterfaceAudience.Public
-public class <a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.52">CopyTable</a>
+public class <a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.54">CopyTable</a>
 extends org.apache.hadoop.conf.Configured
 implements org.apache.hadoop.util.Tool</pre>
 <div class="block">Tool used to copy a table to another one which can be on a different setup.
@@ -218,7 +218,7 @@ implements org.apache.hadoop.util.Tool</pre>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>CopyTable</h4>
-<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.52">CopyTable</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.54">CopyTable</a>()</pre>
 </li>
 </ul>
 </li>
@@ -235,7 +235,7 @@ implements org.apache.hadoop.util.Tool</pre>
 <ul class="blockList">
 <li class="blockList">
 <h4>createSubmittableJob</h4>
-<pre>public&nbsp;org.apache.hadoop.mapreduce.Job&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.82">createSubmittableJob</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>[]&nbsp;args)
+<pre>public&nbsp;org.apache.hadoop.mapreduce.Job&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.110">createSubmittableJob</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>[]&nbsp;args)
                                                      throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Sets up the actual job.</div>
 <dl>
@@ -254,7 +254,7 @@ implements org.apache.hadoop.util.Tool</pre>
 <ul class="blockList">
 <li class="blockList">
 <h4>main</h4>
-<pre>public static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.356">main</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>[]&nbsp;args)
+<pre>public static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.400">main</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>[]&nbsp;args)
                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Exception.html?is-external=true" title="class or interface in java.lang">Exception</a></pre>
 <div class="block">Main entry point.</div>
 <dl>
@@ -271,7 +271,7 @@ implements org.apache.hadoop.util.Tool</pre>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>run</h4>
-<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.362">run</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>[]&nbsp;args)
+<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html#line.406">run</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>[]&nbsp;args)
         throws <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Exception.html?is-external=true" title="class or interface in java.lang">Exception</a></pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>

http://git-wip-us.apache.org/repos/asf/hbase-site/blob/09ea0d5f/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html
----------------------------------------------------------------------
diff --git a/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html b/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html
index e2ca07a..333ff45 100644
--- a/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html
+++ b/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/CopyTable.html
@@ -29,7 +29,7 @@
 <span class="sourceLineNo">021</span>import java.io.IOException;<a name="line.21"></a>
 <span class="sourceLineNo">022</span>import java.util.HashMap;<a name="line.22"></a>
 <span class="sourceLineNo">023</span>import java.util.Map;<a name="line.23"></a>
-<span class="sourceLineNo">024</span>import java.util.Random;<a name="line.24"></a>
+<span class="sourceLineNo">024</span>import java.util.UUID;<a name="line.24"></a>
 <span class="sourceLineNo">025</span><a name="line.25"></a>
 <span class="sourceLineNo">026</span>import org.apache.hadoop.conf.Configured;<a name="line.26"></a>
 <span class="sourceLineNo">027</span>import org.apache.hadoop.fs.FileSystem;<a name="line.27"></a>
@@ -37,363 +37,410 @@
 <span class="sourceLineNo">029</span>import org.apache.hadoop.hbase.HBaseConfiguration;<a name="line.29"></a>
 <span class="sourceLineNo">030</span>import org.apache.hadoop.hbase.HConstants;<a name="line.30"></a>
 <span class="sourceLineNo">031</span>import org.apache.hadoop.hbase.TableName;<a name="line.31"></a>
-<span class="sourceLineNo">032</span>import org.apache.hadoop.hbase.util.FSUtils;<a name="line.32"></a>
-<span class="sourceLineNo">033</span>import org.apache.yetus.audience.InterfaceAudience;<a name="line.33"></a>
-<span class="sourceLineNo">034</span>import org.slf4j.Logger;<a name="line.34"></a>
-<span class="sourceLineNo">035</span>import org.slf4j.LoggerFactory;<a name="line.35"></a>
-<span class="sourceLineNo">036</span>import org.apache.hadoop.hbase.client.Admin;<a name="line.36"></a>
-<span class="sourceLineNo">037</span>import org.apache.hadoop.hbase.client.Connection;<a name="line.37"></a>
-<span class="sourceLineNo">038</span>import org.apache.hadoop.hbase.client.ConnectionFactory;<a name="line.38"></a>
-<span class="sourceLineNo">039</span>import org.apache.hadoop.hbase.client.Scan;<a name="line.39"></a>
-<span class="sourceLineNo">040</span>import org.apache.hadoop.hbase.tool.LoadIncrementalHFiles;<a name="line.40"></a>
-<span class="sourceLineNo">041</span>import org.apache.hadoop.hbase.util.Bytes;<a name="line.41"></a>
-<span class="sourceLineNo">042</span>import org.apache.hadoop.mapreduce.Job;<a name="line.42"></a>
-<span class="sourceLineNo">043</span>import org.apache.hadoop.util.Tool;<a name="line.43"></a>
-<span class="sourceLineNo">044</span>import org.apache.hadoop.util.ToolRunner;<a name="line.44"></a>
-<span class="sourceLineNo">045</span><a name="line.45"></a>
-<span class="sourceLineNo">046</span>/**<a name="line.46"></a>
-<span class="sourceLineNo">047</span> * Tool used to copy a table to another one which can be on a different setup.<a name="line.47"></a>
-<span class="sourceLineNo">048</span> * It is also configurable with a start and time as well as a specification<a name="line.48"></a>
-<span class="sourceLineNo">049</span> * of the region server implementation if different from the local cluster.<a name="line.49"></a>
-<span class="sourceLineNo">050</span> */<a name="line.50"></a>
-<span class="sourceLineNo">051</span>@InterfaceAudience.Public<a name="line.51"></a>
-<span class="sourceLineNo">052</span>public class CopyTable extends Configured implements Tool {<a name="line.52"></a>
-<span class="sourceLineNo">053</span>  private static final Logger LOG = LoggerFactory.getLogger(CopyTable.class);<a name="line.53"></a>
-<span class="sourceLineNo">054</span><a name="line.54"></a>
-<span class="sourceLineNo">055</span>  final static String NAME = "copytable";<a name="line.55"></a>
-<span class="sourceLineNo">056</span>  long startTime = 0;<a name="line.56"></a>
-<span class="sourceLineNo">057</span>  long endTime = HConstants.LATEST_TIMESTAMP;<a name="line.57"></a>
-<span class="sourceLineNo">058</span>  int batch = Integer.MAX_VALUE;<a name="line.58"></a>
-<span class="sourceLineNo">059</span>  int cacheRow = -1;<a name="line.59"></a>
-<span class="sourceLineNo">060</span>  int versions = -1;<a name="line.60"></a>
-<span class="sourceLineNo">061</span>  String tableName = null;<a name="line.61"></a>
-<span class="sourceLineNo">062</span>  String startRow = null;<a name="line.62"></a>
-<span class="sourceLineNo">063</span>  String stopRow = null;<a name="line.63"></a>
-<span class="sourceLineNo">064</span>  String dstTableName = null;<a name="line.64"></a>
-<span class="sourceLineNo">065</span>  String peerAddress = null;<a name="line.65"></a>
-<span class="sourceLineNo">066</span>  String families = null;<a name="line.66"></a>
-<span class="sourceLineNo">067</span>  boolean allCells = false;<a name="line.67"></a>
-<span class="sourceLineNo">068</span>  static boolean shuffle = false;<a name="line.68"></a>
-<span class="sourceLineNo">069</span><a name="line.69"></a>
-<span class="sourceLineNo">070</span>  boolean bulkload = false;<a name="line.70"></a>
-<span class="sourceLineNo">071</span>  Path bulkloadDir = null;<a name="line.71"></a>
-<span class="sourceLineNo">072</span><a name="line.72"></a>
-<span class="sourceLineNo">073</span>  private final static String JOB_NAME_CONF_KEY = "mapreduce.job.name";<a name="line.73"></a>
+<span class="sourceLineNo">032</span>import org.apache.hadoop.hbase.mapreduce.Import.CellImporter;<a name="line.32"></a>
+<span class="sourceLineNo">033</span>import org.apache.hadoop.hbase.mapreduce.Import.Importer;<a name="line.33"></a>
+<span class="sourceLineNo">034</span>import org.apache.hadoop.hbase.util.FSUtils;<a name="line.34"></a>
+<span class="sourceLineNo">035</span>import org.apache.yetus.audience.InterfaceAudience;<a name="line.35"></a>
+<span class="sourceLineNo">036</span>import org.slf4j.Logger;<a name="line.36"></a>
+<span class="sourceLineNo">037</span>import org.slf4j.LoggerFactory;<a name="line.37"></a>
+<span class="sourceLineNo">038</span>import org.apache.hadoop.hbase.client.Admin;<a name="line.38"></a>
+<span class="sourceLineNo">039</span>import org.apache.hadoop.hbase.client.Connection;<a name="line.39"></a>
+<span class="sourceLineNo">040</span>import org.apache.hadoop.hbase.client.ConnectionFactory;<a name="line.40"></a>
+<span class="sourceLineNo">041</span>import org.apache.hadoop.hbase.client.Scan;<a name="line.41"></a>
+<span class="sourceLineNo">042</span>import org.apache.hadoop.hbase.tool.LoadIncrementalHFiles;<a name="line.42"></a>
+<span class="sourceLineNo">043</span>import org.apache.hadoop.hbase.util.Bytes;<a name="line.43"></a>
+<span class="sourceLineNo">044</span>import org.apache.hadoop.mapreduce.Job;<a name="line.44"></a>
+<span class="sourceLineNo">045</span>import org.apache.hadoop.util.Tool;<a name="line.45"></a>
+<span class="sourceLineNo">046</span>import org.apache.hadoop.util.ToolRunner;<a name="line.46"></a>
+<span class="sourceLineNo">047</span><a name="line.47"></a>
+<span class="sourceLineNo">048</span>/**<a name="line.48"></a>
+<span class="sourceLineNo">049</span> * Tool used to copy a table to another one which can be on a different setup.<a name="line.49"></a>
+<span class="sourceLineNo">050</span> * It is also configurable with a start and time as well as a specification<a name="line.50"></a>
+<span class="sourceLineNo">051</span> * of the region server implementation if different from the local cluster.<a name="line.51"></a>
+<span class="sourceLineNo">052</span> */<a name="line.52"></a>
+<span class="sourceLineNo">053</span>@InterfaceAudience.Public<a name="line.53"></a>
+<span class="sourceLineNo">054</span>public class CopyTable extends Configured implements Tool {<a name="line.54"></a>
+<span class="sourceLineNo">055</span>  private static final Logger LOG = LoggerFactory.getLogger(CopyTable.class);<a name="line.55"></a>
+<span class="sourceLineNo">056</span><a name="line.56"></a>
+<span class="sourceLineNo">057</span>  final static String NAME = "copytable";<a name="line.57"></a>
+<span class="sourceLineNo">058</span>  long startTime = 0;<a name="line.58"></a>
+<span class="sourceLineNo">059</span>  long endTime = HConstants.LATEST_TIMESTAMP;<a name="line.59"></a>
+<span class="sourceLineNo">060</span>  int batch = Integer.MAX_VALUE;<a name="line.60"></a>
+<span class="sourceLineNo">061</span>  int cacheRow = -1;<a name="line.61"></a>
+<span class="sourceLineNo">062</span>  int versions = -1;<a name="line.62"></a>
+<span class="sourceLineNo">063</span>  String tableName = null;<a name="line.63"></a>
+<span class="sourceLineNo">064</span>  String startRow = null;<a name="line.64"></a>
+<span class="sourceLineNo">065</span>  String stopRow = null;<a name="line.65"></a>
+<span class="sourceLineNo">066</span>  String dstTableName = null;<a name="line.66"></a>
+<span class="sourceLineNo">067</span>  String peerAddress = null;<a name="line.67"></a>
+<span class="sourceLineNo">068</span>  String families = null;<a name="line.68"></a>
+<span class="sourceLineNo">069</span>  boolean allCells = false;<a name="line.69"></a>
+<span class="sourceLineNo">070</span>  static boolean shuffle = false;<a name="line.70"></a>
+<span class="sourceLineNo">071</span><a name="line.71"></a>
+<span class="sourceLineNo">072</span>  boolean bulkload = false;<a name="line.72"></a>
+<span class="sourceLineNo">073</span>  Path bulkloadDir = null;<a name="line.73"></a>
 <span class="sourceLineNo">074</span><a name="line.74"></a>
-<span class="sourceLineNo">075</span>  /**<a name="line.75"></a>
-<span class="sourceLineNo">076</span>   * Sets up the actual job.<a name="line.76"></a>
-<span class="sourceLineNo">077</span>   *<a name="line.77"></a>
-<span class="sourceLineNo">078</span>   * @param args  The command line parameters.<a name="line.78"></a>
-<span class="sourceLineNo">079</span>   * @return The newly created job.<a name="line.79"></a>
-<span class="sourceLineNo">080</span>   * @throws IOException When setting up the job fails.<a name="line.80"></a>
-<span class="sourceLineNo">081</span>   */<a name="line.81"></a>
-<span class="sourceLineNo">082</span>  public Job createSubmittableJob(String[] args)<a name="line.82"></a>
-<span class="sourceLineNo">083</span>  throws IOException {<a name="line.83"></a>
-<span class="sourceLineNo">084</span>    if (!doCommandLine(args)) {<a name="line.84"></a>
-<span class="sourceLineNo">085</span>      return null;<a name="line.85"></a>
-<span class="sourceLineNo">086</span>    }<a name="line.86"></a>
-<span class="sourceLineNo">087</span><a name="line.87"></a>
-<span class="sourceLineNo">088</span>    Job job = Job.getInstance(getConf(), getConf().get(JOB_NAME_CONF_KEY, NAME + "_" + tableName));<a name="line.88"></a>
-<span class="sourceLineNo">089</span>    job.setJarByClass(CopyTable.class);<a name="line.89"></a>
-<span class="sourceLineNo">090</span>    Scan scan = new Scan();<a name="line.90"></a>
-<span class="sourceLineNo">091</span><a name="line.91"></a>
-<span class="sourceLineNo">092</span>    scan.setBatch(batch);<a name="line.92"></a>
-<span class="sourceLineNo">093</span>    scan.setCacheBlocks(false);<a name="line.93"></a>
-<span class="sourceLineNo">094</span><a name="line.94"></a>
-<span class="sourceLineNo">095</span>    if (cacheRow &gt; 0) {<a name="line.95"></a>
-<span class="sourceLineNo">096</span>      scan.setCaching(cacheRow);<a name="line.96"></a>
-<span class="sourceLineNo">097</span>    } else {<a name="line.97"></a>
-<span class="sourceLineNo">098</span>      scan.setCaching(getConf().getInt(HConstants.HBASE_CLIENT_SCANNER_CACHING, 100));<a name="line.98"></a>
-<span class="sourceLineNo">099</span>    }<a name="line.99"></a>
-<span class="sourceLineNo">100</span><a name="line.100"></a>
-<span class="sourceLineNo">101</span>    scan.setTimeRange(startTime, endTime);<a name="line.101"></a>
+<span class="sourceLineNo">075</span>  boolean readingSnapshot = false;<a name="line.75"></a>
+<span class="sourceLineNo">076</span>  String snapshot = null;<a name="line.76"></a>
+<span class="sourceLineNo">077</span><a name="line.77"></a>
+<span class="sourceLineNo">078</span>  private final static String JOB_NAME_CONF_KEY = "mapreduce.job.name";<a name="line.78"></a>
+<span class="sourceLineNo">079</span><a name="line.79"></a>
+<span class="sourceLineNo">080</span>  private Path generateUniqTempDir(boolean withDirCreated) throws IOException {<a name="line.80"></a>
+<span class="sourceLineNo">081</span>    FileSystem fs = FSUtils.getCurrentFileSystem(getConf());<a name="line.81"></a>
+<span class="sourceLineNo">082</span>    Path dir = new Path(fs.getWorkingDirectory(), NAME);<a name="line.82"></a>
+<span class="sourceLineNo">083</span>    if (!fs.exists(dir)) {<a name="line.83"></a>
+<span class="sourceLineNo">084</span>      fs.mkdirs(dir);<a name="line.84"></a>
+<span class="sourceLineNo">085</span>    }<a name="line.85"></a>
+<span class="sourceLineNo">086</span>    Path newDir = new Path(dir, UUID.randomUUID().toString());<a name="line.86"></a>
+<span class="sourceLineNo">087</span>    if (withDirCreated) {<a name="line.87"></a>
+<span class="sourceLineNo">088</span>      fs.mkdirs(newDir);<a name="line.88"></a>
+<span class="sourceLineNo">089</span>    }<a name="line.89"></a>
+<span class="sourceLineNo">090</span>    return newDir;<a name="line.90"></a>
+<span class="sourceLineNo">091</span>  }<a name="line.91"></a>
+<span class="sourceLineNo">092</span><a name="line.92"></a>
+<span class="sourceLineNo">093</span>  private void initCopyTableMapperReducerJob(Job job, Scan scan) throws IOException {<a name="line.93"></a>
+<span class="sourceLineNo">094</span>    Class&lt;? extends TableMapper&gt; mapper = bulkload ? CellImporter.class : Importer.class;<a name="line.94"></a>
+<span class="sourceLineNo">095</span>    if (readingSnapshot) {<a name="line.95"></a>
+<span class="sourceLineNo">096</span>      TableMapReduceUtil.initTableSnapshotMapperJob(snapshot, scan, mapper, null, null, job, true,<a name="line.96"></a>
+<span class="sourceLineNo">097</span>        generateUniqTempDir(true));<a name="line.97"></a>
+<span class="sourceLineNo">098</span>    } else {<a name="line.98"></a>
+<span class="sourceLineNo">099</span>      TableMapReduceUtil.initTableMapperJob(tableName, scan, mapper, null, null, job);<a name="line.99"></a>
+<span class="sourceLineNo">100</span>    }<a name="line.100"></a>
+<span class="sourceLineNo">101</span>  }<a name="line.101"></a>
 <span class="sourceLineNo">102</span><a name="line.102"></a>
-<span class="sourceLineNo">103</span>    if (allCells) {<a name="line.103"></a>
-<span class="sourceLineNo">104</span>      scan.setRaw(true);<a name="line.104"></a>
-<span class="sourceLineNo">105</span>    }<a name="line.105"></a>
-<span class="sourceLineNo">106</span>    if (shuffle) {<a name="line.106"></a>
-<span class="sourceLineNo">107</span>      job.getConfiguration().set(TableInputFormat.SHUFFLE_MAPS, "true");<a name="line.107"></a>
-<span class="sourceLineNo">108</span>    }<a name="line.108"></a>
-<span class="sourceLineNo">109</span>    if (versions &gt;= 0) {<a name="line.109"></a>
-<span class="sourceLineNo">110</span>      scan.setMaxVersions(versions);<a name="line.110"></a>
-<span class="sourceLineNo">111</span>    }<a name="line.111"></a>
-<span class="sourceLineNo">112</span><a name="line.112"></a>
-<span class="sourceLineNo">113</span>    if (startRow != null) {<a name="line.113"></a>
-<span class="sourceLineNo">114</span>      scan.setStartRow(Bytes.toBytesBinary(startRow));<a name="line.114"></a>
-<span class="sourceLineNo">115</span>    }<a name="line.115"></a>
-<span class="sourceLineNo">116</span><a name="line.116"></a>
-<span class="sourceLineNo">117</span>    if (stopRow != null) {<a name="line.117"></a>
-<span class="sourceLineNo">118</span>      scan.setStopRow(Bytes.toBytesBinary(stopRow));<a name="line.118"></a>
-<span class="sourceLineNo">119</span>    }<a name="line.119"></a>
-<span class="sourceLineNo">120</span><a name="line.120"></a>
-<span class="sourceLineNo">121</span>    if(families != null) {<a name="line.121"></a>
-<span class="sourceLineNo">122</span>      String[] fams = families.split(",");<a name="line.122"></a>
-<span class="sourceLineNo">123</span>      Map&lt;String,String&gt; cfRenameMap = new HashMap&lt;&gt;();<a name="line.123"></a>
-<span class="sourceLineNo">124</span>      for(String fam : fams) {<a name="line.124"></a>
-<span class="sourceLineNo">125</span>        String sourceCf;<a name="line.125"></a>
-<span class="sourceLineNo">126</span>        if(fam.contains(":")) {<a name="line.126"></a>
-<span class="sourceLineNo">127</span>            // fam looks like "sourceCfName:destCfName"<a name="line.127"></a>
-<span class="sourceLineNo">128</span>            String[] srcAndDest = fam.split(":", 2);<a name="line.128"></a>
-<span class="sourceLineNo">129</span>            sourceCf = srcAndDest[0];<a name="line.129"></a>
-<span class="sourceLineNo">130</span>            String destCf = srcAndDest[1];<a name="line.130"></a>
-<span class="sourceLineNo">131</span>            cfRenameMap.put(sourceCf, destCf);<a name="line.131"></a>
-<span class="sourceLineNo">132</span>        } else {<a name="line.132"></a>
-<span class="sourceLineNo">133</span>            // fam is just "sourceCf"<a name="line.133"></a>
-<span class="sourceLineNo">134</span>            sourceCf = fam;<a name="line.134"></a>
-<span class="sourceLineNo">135</span>        }<a name="line.135"></a>
-<span class="sourceLineNo">136</span>        scan.addFamily(Bytes.toBytes(sourceCf));<a name="line.136"></a>
-<span class="sourceLineNo">137</span>      }<a name="line.137"></a>
-<span class="sourceLineNo">138</span>      Import.configureCfRenaming(job.getConfiguration(), cfRenameMap);<a name="line.138"></a>
+<span class="sourceLineNo">103</span>  /**<a name="line.103"></a>
+<span class="sourceLineNo">104</span>   * Sets up the actual job.<a name="line.104"></a>
+<span class="sourceLineNo">105</span>   *<a name="line.105"></a>
+<span class="sourceLineNo">106</span>   * @param args  The command line parameters.<a name="line.106"></a>
+<span class="sourceLineNo">107</span>   * @return The newly created job.<a name="line.107"></a>
+<span class="sourceLineNo">108</span>   * @throws IOException When setting up the job fails.<a name="line.108"></a>
+<span class="sourceLineNo">109</span>   */<a name="line.109"></a>
+<span class="sourceLineNo">110</span>  public Job createSubmittableJob(String[] args) throws IOException {<a name="line.110"></a>
+<span class="sourceLineNo">111</span>    if (!doCommandLine(args)) {<a name="line.111"></a>
+<span class="sourceLineNo">112</span>      return null;<a name="line.112"></a>
+<span class="sourceLineNo">113</span>    }<a name="line.113"></a>
+<span class="sourceLineNo">114</span><a name="line.114"></a>
+<span class="sourceLineNo">115</span>    String jobName = NAME + "_" + (tableName == null ? snapshot : tableName);<a name="line.115"></a>
+<span class="sourceLineNo">116</span>    Job job = Job.getInstance(getConf(), getConf().get(JOB_NAME_CONF_KEY, jobName));<a name="line.116"></a>
+<span class="sourceLineNo">117</span>    job.setJarByClass(CopyTable.class);<a name="line.117"></a>
+<span class="sourceLineNo">118</span>    Scan scan = new Scan();<a name="line.118"></a>
+<span class="sourceLineNo">119</span><a name="line.119"></a>
+<span class="sourceLineNo">120</span>    scan.setBatch(batch);<a name="line.120"></a>
+<span class="sourceLineNo">121</span>    scan.setCacheBlocks(false);<a name="line.121"></a>
+<span class="sourceLineNo">122</span><a name="line.122"></a>
+<span class="sourceLineNo">123</span>    if (cacheRow &gt; 0) {<a name="line.123"></a>
+<span class="sourceLineNo">124</span>      scan.setCaching(cacheRow);<a name="line.124"></a>
+<span class="sourceLineNo">125</span>    } else {<a name="line.125"></a>
+<span class="sourceLineNo">126</span>      scan.setCaching(getConf().getInt(HConstants.HBASE_CLIENT_SCANNER_CACHING, 100));<a name="line.126"></a>
+<span class="sourceLineNo">127</span>    }<a name="line.127"></a>
+<span class="sourceLineNo">128</span><a name="line.128"></a>
+<span class="sourceLineNo">129</span>    scan.setTimeRange(startTime, endTime);<a name="line.129"></a>
+<span class="sourceLineNo">130</span><a name="line.130"></a>
+<span class="sourceLineNo">131</span>    if (allCells) {<a name="line.131"></a>
+<span class="sourceLineNo">132</span>      scan.setRaw(true);<a name="line.132"></a>
+<span class="sourceLineNo">133</span>    }<a name="line.133"></a>
+<span class="sourceLineNo">134</span>    if (shuffle) {<a name="line.134"></a>
+<span class="sourceLineNo">135</span>      job.getConfiguration().set(TableInputFormat.SHUFFLE_MAPS, "true");<a name="line.135"></a>
+<span class="sourceLineNo">136</span>    }<a name="line.136"></a>
+<span class="sourceLineNo">137</span>    if (versions &gt;= 0) {<a name="line.137"></a>
+<span class="sourceLineNo">138</span>      scan.readVersions(versions);<a name="line.138"></a>
 <span class="sourceLineNo">139</span>    }<a name="line.139"></a>
-<span class="sourceLineNo">140</span>    job.setNumReduceTasks(0);<a name="line.140"></a>
-<span class="sourceLineNo">141</span><a name="line.141"></a>
-<span class="sourceLineNo">142</span>    if (bulkload) {<a name="line.142"></a>
-<span class="sourceLineNo">143</span>      TableMapReduceUtil.initTableMapperJob(tableName, scan, Import.CellImporter.class, null, null,<a name="line.143"></a>
-<span class="sourceLineNo">144</span>        job);<a name="line.144"></a>
-<span class="sourceLineNo">145</span><a name="line.145"></a>
-<span class="sourceLineNo">146</span>      // We need to split the inputs by destination tables so that output of Map can be bulk-loaded.<a name="line.146"></a>
-<span class="sourceLineNo">147</span>      TableInputFormat.configureSplitTable(job, TableName.valueOf(dstTableName));<a name="line.147"></a>
+<span class="sourceLineNo">140</span><a name="line.140"></a>
+<span class="sourceLineNo">141</span>    if (startRow != null) {<a name="line.141"></a>
+<span class="sourceLineNo">142</span>      scan.withStartRow(Bytes.toBytesBinary(startRow));<a name="line.142"></a>
+<span class="sourceLineNo">143</span>    }<a name="line.143"></a>
+<span class="sourceLineNo">144</span><a name="line.144"></a>
+<span class="sourceLineNo">145</span>    if (stopRow != null) {<a name="line.145"></a>
+<span class="sourceLineNo">146</span>      scan.withStopRow(Bytes.toBytesBinary(stopRow));<a name="line.146"></a>
+<span class="sourceLineNo">147</span>    }<a name="line.147"></a>
 <span class="sourceLineNo">148</span><a name="line.148"></a>
-<span class="sourceLineNo">149</span>      FileSystem fs = FSUtils.getCurrentFileSystem(getConf());<a name="line.149"></a>
-<span class="sourceLineNo">150</span>      Random rand = new Random();<a name="line.150"></a>
-<span class="sourceLineNo">151</span>      Path root = new Path(fs.getWorkingDirectory(), "copytable");<a name="line.151"></a>
-<span class="sourceLineNo">152</span>      fs.mkdirs(root);<a name="line.152"></a>
-<span class="sourceLineNo">153</span>      while (true) {<a name="line.153"></a>
-<span class="sourceLineNo">154</span>        bulkloadDir = new Path(root, "" + rand.nextLong());<a name="line.154"></a>
-<span class="sourceLineNo">155</span>        if (!fs.exists(bulkloadDir)) {<a name="line.155"></a>
-<span class="sourceLineNo">156</span>          break;<a name="line.156"></a>
-<span class="sourceLineNo">157</span>        }<a name="line.157"></a>
-<span class="sourceLineNo">158</span>      }<a name="line.158"></a>
-<span class="sourceLineNo">159</span><a name="line.159"></a>
-<span class="sourceLineNo">160</span>      System.out.println("HFiles will be stored at " + this.bulkloadDir);<a name="line.160"></a>
-<span class="sourceLineNo">161</span>      HFileOutputFormat2.setOutputPath(job, bulkloadDir);<a name="line.161"></a>
-<span class="sourceLineNo">162</span>      try (Connection conn = ConnectionFactory.createConnection(getConf());<a name="line.162"></a>
-<span class="sourceLineNo">163</span>          Admin admin = conn.getAdmin()) {<a name="line.163"></a>
-<span class="sourceLineNo">164</span>        HFileOutputFormat2.configureIncrementalLoadMap(job,<a name="line.164"></a>
-<span class="sourceLineNo">165</span>          admin.getDescriptor((TableName.valueOf(dstTableName))));<a name="line.165"></a>
-<span class="sourceLineNo">166</span>      }<a name="line.166"></a>
-<span class="sourceLineNo">167</span>    } else {<a name="line.167"></a>
-<span class="sourceLineNo">168</span>      TableMapReduceUtil.initTableMapperJob(tableName, scan,<a name="line.168"></a>
-<span class="sourceLineNo">169</span>        Import.Importer.class, null, null, job);<a name="line.169"></a>
-<span class="sourceLineNo">170</span><a name="line.170"></a>
-<span class="sourceLineNo">171</span>      TableMapReduceUtil.initTableReducerJob(dstTableName, null, job, null, peerAddress, null,<a name="line.171"></a>
-<span class="sourceLineNo">172</span>        null);<a name="line.172"></a>
-<span class="sourceLineNo">173</span>    }<a name="line.173"></a>
-<span class="sourceLineNo">174</span><a name="line.174"></a>
-<span class="sourceLineNo">175</span>    return job;<a name="line.175"></a>
-<span class="sourceLineNo">176</span>  }<a name="line.176"></a>
-<span class="sourceLineNo">177</span><a name="line.177"></a>
-<span class="sourceLineNo">178</span>  /*<a name="line.178"></a>
-<span class="sourceLineNo">179</span>   * @param errorMsg Error message.  Can be null.<a name="line.179"></a>
-<span class="sourceLineNo">180</span>   */<a name="line.180"></a>
-<span class="sourceLineNo">181</span>  private static void printUsage(final String errorMsg) {<a name="line.181"></a>
-<span class="sourceLineNo">182</span>    if (errorMsg != null &amp;&amp; errorMsg.length() &gt; 0) {<a name="line.182"></a>
-<span class="sourceLineNo">183</span>      System.err.println("ERROR: " + errorMsg);<a name="line.183"></a>
-<span class="sourceLineNo">184</span>    }<a name="line.184"></a>
-<span class="sourceLineNo">185</span>    System.err.println("Usage: CopyTable [general options] [--starttime=X] [--endtime=Y] " +<a name="line.185"></a>
-<span class="sourceLineNo">186</span>        "[--new.name=NEW] [--peer.adr=ADR] &lt;tablename&gt;");<a name="line.186"></a>
-<span class="sourceLineNo">187</span>    System.err.println();<a name="line.187"></a>
-<span class="sourceLineNo">188</span>    System.err.println("Options:");<a name="line.188"></a>
-<span class="sourceLineNo">189</span>    System.err.println(" rs.class     hbase.regionserver.class of the peer cluster");<a name="line.189"></a>
-<span class="sourceLineNo">190</span>    System.err.println("              specify if different from current cluster");<a name="line.190"></a>
-<span class="sourceLineNo">191</span>    System.err.println(" rs.impl      hbase.regionserver.impl of the peer cluster");<a name="line.191"></a>
-<span class="sourceLineNo">192</span>    System.err.println(" startrow     the start row");<a name="line.192"></a>
-<span class="sourceLineNo">193</span>    System.err.println(" stoprow      the stop row");<a name="line.193"></a>
-<span class="sourceLineNo">194</span>    System.err.println(" starttime    beginning of the time range (unixtime in millis)");<a name="line.194"></a>
-<span class="sourceLineNo">195</span>    System.err.println("              without endtime means from starttime to forever");<a name="line.195"></a>
-<span class="sourceLineNo">196</span>    System.err.println(" endtime      end of the time range.  Ignored if no starttime specified.");<a name="line.196"></a>
-<span class="sourceLineNo">197</span>    System.err.println(" versions     number of cell versions to copy");<a name="line.197"></a>
-<span class="sourceLineNo">198</span>    System.err.println(" new.name     new table's name");<a name="line.198"></a>
-<span class="sourceLineNo">199</span>    System.err.println(" peer.adr     Address of the peer cluster given in the format");<a name="line.199"></a>
-<span class="sourceLineNo">200</span>    System.err.println("              hbase.zookeeper.quorum:hbase.zookeeper.client"<a name="line.200"></a>
-<span class="sourceLineNo">201</span>        + ".port:zookeeper.znode.parent");<a name="line.201"></a>
-<span class="sourceLineNo">202</span>    System.err.println(" families     comma-separated list of families to copy");<a name="line.202"></a>
-<span class="sourceLineNo">203</span>    System.err.println("              To copy from cf1 to cf2, give sourceCfName:destCfName. ");<a name="line.203"></a>
-<span class="sourceLineNo">204</span>    System.err.println("              To keep the same name, just give \"cfName\"");<a name="line.204"></a>
-<span class="sourceLineNo">205</span>    System.err.println(" all.cells    also copy delete markers and deleted cells");<a name="line.205"></a>
-<span class="sourceLineNo">206</span>    System.err.println(" bulkload     Write input into HFiles and bulk load to the destination "<a name="line.206"></a>
-<span class="sourceLineNo">207</span>        + "table");<a name="line.207"></a>
-<span class="sourceLineNo">208</span>    System.err.println();<a name="line.208"></a>
-<span class="sourceLineNo">209</span>    System.err.println("Args:");<a name="line.209"></a>
-<span class="sourceLineNo">210</span>    System.err.println(" tablename    Name of the table to copy");<a name="line.210"></a>
-<span class="sourceLineNo">211</span>    System.err.println();<a name="line.211"></a>
-<span class="sourceLineNo">212</span>    System.err.println("Examples:");<a name="line.212"></a>
-<span class="sourceLineNo">213</span>    System.err.println(" To copy 'TestTable' to a cluster that uses replication for a 1 hour window:");<a name="line.213"></a>
-<span class="sourceLineNo">214</span>    System.err.println(" $ hbase " +<a name="line.214"></a>
-<span class="sourceLineNo">215</span>        "org.apache.hadoop.hbase.mapreduce.CopyTable --starttime=1265875194289 --endtime=1265878794289 " +<a name="line.215"></a>
-<span class="sourceLineNo">216</span>        "--peer.adr=server1,server2,server3:2181:/hbase --families=myOldCf:myNewCf,cf2,cf3 TestTable ");<a name="line.216"></a>
-<span class="sourceLineNo">217</span>    System.err.println("For performance consider the following general option:\n"<a name="line.217"></a>
-<span class="sourceLineNo">218</span>        + "  It is recommended that you set the following to &gt;=100. A higher value uses more memory but\n"<a name="line.218"></a>
-<span class="sourceLineNo">219</span>        + "  decreases the round trip time to the server and may increase performance.\n"<a name="line.219"></a>
-<span class="sourceLineNo">220</span>        + "    -Dhbase.client.scanner.caching=100\n"<a name="line.220"></a>
-<span class="sourceLineNo">221</span>        + "  The following should always be set to false, to prevent writing data twice, which may produce \n"<a name="line.221"></a>
-<span class="sourceLineNo">222</span>        + "  inaccurate results.\n"<a name="line.222"></a>
-<span class="sourceLineNo">223</span>        + "    -Dmapreduce.map.speculative=false");<a name="line.223"></a>
-<span class="sourceLineNo">224</span>  }<a name="line.224"></a>
-<span class="sourceLineNo">225</span><a name="line.225"></a>
-<span class="sourceLineNo">226</span>  private boolean doCommandLine(final String[] args) {<a name="line.226"></a>
-<span class="sourceLineNo">227</span>    // Process command-line args. TODO: Better cmd-line processing<a name="line.227"></a>
-<span class="sourceLineNo">228</span>    // (but hopefully something not as painful as cli options).<a name="line.228"></a>
-<span class="sourceLineNo">229</span>    if (args.length &lt; 1) {<a name="line.229"></a>
-<span class="sourceLineNo">230</span>      printUsage(null);<a name="line.230"></a>
-<span class="sourceLineNo">231</span>      return false;<a name="line.231"></a>
-<span class="sourceLineNo">232</span>    }<a name="line.232"></a>
-<span class="sourceLineNo">233</span>    try {<a name="line.233"></a>
-<span class="sourceLineNo">234</span>      for (int i = 0; i &lt; args.length; i++) {<a name="line.234"></a>
-<span class="sourceLineNo">235</span>        String cmd = args[i];<a name="line.235"></a>
-<span class="sourceLineNo">236</span>        if (cmd.equals("-h") || cmd.startsWith("--h")) {<a name="line.236"></a>
-<span class="sourceLineNo">237</span>          printUsage(null);<a name="line.237"></a>
-<span class="sourceLineNo">238</span>          return false;<a name="line.238"></a>
-<span class="sourceLineNo">239</span>        }<a name="line.239"></a>
-<span class="sourceLineNo">240</span><a name="line.240"></a>
-<span class="sourceLineNo">241</span>        final String startRowArgKey = "--startrow=";<a name="line.241"></a>
-<span class="sourceLineNo">242</span>        if (cmd.startsWith(startRowArgKey)) {<a name="line.242"></a>
-<span class="sourceLineNo">243</span>          startRow = cmd.substring(startRowArgKey.length());<a name="line.243"></a>
-<span class="sourceLineNo">244</span>          continue;<a name="line.244"></a>
-<span class="sourceLineNo">245</span>        }<a name="line.245"></a>
-<span class="sourceLineNo">246</span><a name="line.246"></a>
-<span class="sourceLineNo">247</span>        final String stopRowArgKey = "--stoprow=";<a name="line.247"></a>
-<span class="sourceLineNo">248</span>        if (cmd.startsWith(stopRowArgKey)) {<a name="line.248"></a>
-<span class="sourceLineNo">249</span>          stopRow = cmd.substring(stopRowArgKey.length());<a name="line.249"></a>
-<span class="sourceLineNo">250</span>          continue;<a name="line.250"></a>
-<span class="sourceLineNo">251</span>        }<a name="line.251"></a>
-<span class="sourceLineNo">252</span><a name="line.252"></a>
-<span class="sourceLineNo">253</span>        final String startTimeArgKey = "--starttime=";<a name="line.253"></a>
-<span class="sourceLineNo">254</span>        if (cmd.startsWith(startTimeArgKey)) {<a name="line.254"></a>
-<span class="sourceLineNo">255</span>          startTime = Long.parseLong(cmd.substring(startTimeArgKey.length()));<a name="line.255"></a>
-<span class="sourceLineNo">256</span>          continue;<a name="line.256"></a>
-<span class="sourceLineNo">257</span>        }<a name="line.257"></a>
-<span class="sourceLineNo">258</span><a name="line.258"></a>
-<span class="sourceLineNo">259</span>        final String endTimeArgKey = "--endtime=";<a name="line.259"></a>
-<span class="sourceLineNo">260</span>        if (cmd.startsWith(endTimeArgKey)) {<a name="line.260"></a>
-<span class="sourceLineNo">261</span>          endTime = Long.parseLong(cmd.substring(endTimeArgKey.length()));<a name="line.261"></a>
-<span class="sourceLineNo">262</span>          continue;<a name="line.262"></a>
-<span class="sourceLineNo">263</span>        }<a name="line.263"></a>
-<span class="sourceLineNo">264</span><a name="line.264"></a>
-<span class="sourceLineNo">265</span>        final String batchArgKey = "--batch=";<a name="line.265"></a>
-<span class="sourceLineNo">266</span>        if (cmd.startsWith(batchArgKey)) {<a name="line.266"></a>
-<span class="sourceLineNo">267</span>          batch = Integer.parseInt(cmd.substring(batchArgKey.length()));<a name="line.267"></a>
-<span class="sourceLineNo">268</span>          continue;<a name="line.268"></a>
-<span class="sourceLineNo">269</span>        }<a name="line.269"></a>
-<span class="sourceLineNo">270</span><a name="line.270"></a>
-<span class="sourceLineNo">271</span>        final String cacheRowArgKey = "--cacheRow=";<a name="line.271"></a>
-<span class="sourceLineNo">272</span>        if (cmd.startsWith(cacheRowArgKey)) {<a name="line.272"></a>
-<span class="sourceLineNo">273</span>          cacheRow = Integer.parseInt(cmd.substring(cacheRowArgKey.length()));<a name="line.273"></a>
-<span class="sourceLineNo">274</span>          continue;<a name="line.274"></a>
-<span class="sourceLineNo">275</span>        }<a name="line.275"></a>
-<span class="sourceLineNo">276</span><a name="line.276"></a>
-<span class="sourceLineNo">277</span>        final String versionsArgKey = "--versions=";<a name="line.277"></a>
-<span class="sourceLineNo">278</span>        if (cmd.startsWith(versionsArgKey)) {<a name="line.278"></a>
-<span class="sourceLineNo">279</span>          versions = Integer.parseInt(cmd.substring(versionsArgKey.length()));<a name="line.279"></a>
-<span class="sourceLineNo">280</span>          continue;<a name="line.280"></a>
-<span class="sourceLineNo">281</span>        }<a name="line.281"></a>
-<span class="sourceLineNo">282</span><a name="line.282"></a>
-<span class="sourceLineNo">283</span>        final String newNameArgKey = "--new.name=";<a name="line.283"></a>
-<span class="sourceLineNo">284</span>        if (cmd.startsWith(newNameArgKey)) {<a name="line.284"></a>
-<span class="sourceLineNo">285</span>          dstTableName = cmd.substring(newNameArgKey.length());<a name="line.285"></a>
-<span class="sourceLineNo">286</span>          continue;<a name="line.286"></a>
-<span class="sourceLineNo">287</span>        }<a name="line.287"></a>
-<span class="sourceLineNo">288</span><a name="line.288"></a>
-<span class="sourceLineNo">289</span>        final String peerAdrArgKey = "--peer.adr=";<a name="line.289"></a>
-<span class="sourceLineNo">290</span>        if (cmd.startsWith(peerAdrArgKey)) {<a name="line.290"></a>
-<span class="sourceLineNo">291</span>          peerAddress = cmd.substring(peerAdrArgKey.length());<a name="line.291"></a>
-<span class="sourceLineNo">292</span>          continue;<a name="line.292"></a>
-<span class="sourceLineNo">293</span>        }<a name="line.293"></a>
-<span class="sourceLineNo">294</span><a name="line.294"></a>
-<span class="sourceLineNo">295</span>        final String familiesArgKey = "--families=";<a name="line.295"></a>
-<span class="sourceLineNo">296</span>        if (cmd.startsWith(familiesArgKey)) {<a name="line.296"></a>
-<span class="sourceLineNo">297</span>          families = cmd.substring(familiesArgKey.length());<a name="line.297"></a>
-<span class="sourceLineNo">298</span>          continue;<a name="line.298"></a>
-<span class="sourceLineNo">299</span>        }<a name="line.299"></a>
-<span class="sourceLineNo">300</span><a name="line.300"></a>
-<span class="sourceLineNo">301</span>        if (cmd.startsWith("--all.cells")) {<a name="line.301"></a>
-<span class="sourceLineNo">302</span>          allCells = true;<a name="line.302"></a>
-<span class="sourceLineNo">303</span>          continue;<a name="line.303"></a>
-<span class="sourceLineNo">304</span>        }<a name="line.304"></a>
-<span class="sourceLineNo">305</span><a name="line.305"></a>
-<span class="sourceLineNo">306</span>        if (cmd.startsWith("--bulkload")) {<a name="line.306"></a>
-<span class="sourceLineNo">307</span>          bulkload = true;<a name="line.307"></a>
-<span class="sourceLineNo">308</span>          continue;<a name="line.308"></a>
-<span class="sourceLineNo">309</span>        }<a name="line.309"></a>
-<span class="sourceLineNo">310</span><a name="line.310"></a>
-<span class="sourceLineNo">311</span>        if (cmd.startsWith("--shuffle")) {<a name="line.311"></a>
-<span class="sourceLineNo">312</span>          shuffle = true;<a name="line.312"></a>
-<span class="sourceLineNo">313</span>          continue;<a name="line.313"></a>
-<span class="sourceLineNo">314</span>        }<a name="line.314"></a>
-<span class="sourceLineNo">315</span><a name="line.315"></a>
-<span class="sourceLineNo">316</span>        if (i == args.length-1) {<a name="line.316"></a>
-<span class="sourceLineNo">317</span>          tableName = cmd;<a name="line.317"></a>
-<span class="sourceLineNo">318</span>        } else {<a name="line.318"></a>
-<span class="sourceLineNo">319</span>          printUsage("Invalid argument '" + cmd + "'");<a name="line.319"></a>
-<span class="sourceLineNo">320</span>          return false;<a name="line.320"></a>
-<span class="sourceLineNo">321</span>        }<a name="line.321"></a>
-<span class="sourceLineNo">322</span>      }<a name="line.322"></a>
-<span class="sourceLineNo">323</span>      if (dstTableName == null &amp;&amp; peerAddress == null) {<a name="line.323"></a>
-<span class="sourceLineNo">324</span>        printUsage("At least a new table name or a " +<a name="line.324"></a>
-<span class="sourceLineNo">325</span>            "peer address must be specified");<a name="line.325"></a>
-<span class="sourceLineNo">326</span>        return false;<a name="line.326"></a>
-<span class="sourceLineNo">327</span>      }<a name="line.327"></a>
-<span class="sourceLineNo">328</span>      if ((endTime != 0) &amp;&amp; (startTime &gt; endTime)) {<a name="line.328"></a>
-<span class="sourceLineNo">329</span>        printUsage("Invalid time range filter: starttime=" + startTime + " &gt;  endtime=" + endTime);<a name="line.329"></a>
-<span class="sourceLineNo">330</span>        return false;<a name="line.330"></a>
-<span class="sourceLineNo">331</span>      }<a name="line.331"></a>
-<span class="sourceLineNo">332</span><a name="line.332"></a>
-<span class="sourceLineNo">333</span>      if (bulkload &amp;&amp; peerAddress != null) {<a name="line.333"></a>
-<span class="sourceLineNo">334</span>        printUsage("Remote bulkload is not supported!");<a name="line.334"></a>
-<span class="sourceLineNo">335</span>        return false;<a name="line.335"></a>
-<span class="sourceLineNo">336</span>      }<a name="line.336"></a>
-<span class="sourceLineNo">337</span><a name="line.337"></a>
-<span class="sourceLineNo">338</span>      // set dstTableName if necessary<a name="line.338"></a>
-<span class="sourceLineNo">339</span>      if (dstTableName == null) {<a name="line.339"></a>
-<span class="sourceLineNo">340</span>        dstTableName = tableName;<a name="line.340"></a>
-<span class="sourceLineNo">341</span>      }<a name="line.341"></a>
-<span class="sourceLineNo">342</span>    } catch (Exception e) {<a name="line.342"></a>
-<span class="sourceLineNo">343</span>      LOG.error("Failed to parse commandLine arguments", e);<a name="line.343"></a>
-<span class="sourceLineNo">344</span>      printUsage("Can't start because " + e.getMessage());<a name="line.344"></a>
-<span class="sourceLineNo">345</span>      return false;<a name="line.345"></a>
-<span class="sourceLineNo">346</span>    }<a name="line.346"></a>
-<span class="sourceLineNo">347</span>    return true;<a name="line.347"></a>
-<span class="sourceLineNo">348</span>  }<a name="line.348"></a>
-<span class="sourceLineNo">349</span><a name="line.349"></a>
-<span class="sourceLineNo">350</span>  /**<a name="line.350"></a>
-<span class="sourceLineNo">351</span>   * Main entry point.<a name="line.351"></a>
-<span class="sourceLineNo">352</span>   *<a name="line.352"></a>
-<span class="sourceLineNo">353</span>   * @param args  The command line parameters.<a name="line.353"></a>
-<span class="sourceLineNo">354</span>   * @throws Exception When running the job fails.<a name="line.354"></a>
-<span class="sourceLineNo">355</span>   */<a name="line.355"></a>
-<span class="sourceLineNo">356</span>  public static void main(String[] args) throws Exception {<a name="line.356"></a>
-<span class="sourceLineNo">357</span>    int ret = ToolRunner.run(HBaseConfiguration.create(), new CopyTable(), args);<a name="line.357"></a>
-<span class="sourceLineNo">358</span>    System.exit(ret);<a name="line.358"></a>
-<span class="sourceLineNo">359</span>  }<a name="line.359"></a>
+<span class="sourceLineNo">149</span>    if(families != null) {<a name="line.149"></a>
+<span class="sourceLineNo">150</span>      String[] fams = families.split(",");<a name="line.150"></a>
+<span class="sourceLineNo">151</span>      Map&lt;String,String&gt; cfRenameMap = new HashMap&lt;&gt;();<a name="line.151"></a>
+<span class="sourceLineNo">152</span>      for(String fam : fams) {<a name="line.152"></a>
+<span class="sourceLineNo">153</span>        String sourceCf;<a name="line.153"></a>
+<span class="sourceLineNo">154</span>        if(fam.contains(":")) {<a name="line.154"></a>
+<span class="sourceLineNo">155</span>            // fam looks like "sourceCfName:destCfName"<a name="line.155"></a>
+<span class="sourceLineNo">156</span>            String[] srcAndDest = fam.split(":", 2);<a name="line.156"></a>
+<span class="sourceLineNo">157</span>            sourceCf = srcAndDest[0];<a name="line.157"></a>
+<span class="sourceLineNo">158</span>            String destCf = srcAndDest[1];<a name="line.158"></a>
+<span class="sourceLineNo">159</span>            cfRenameMap.put(sourceCf, destCf);<a name="line.159"></a>
+<span class="sourceLineNo">160</span>        } else {<a name="line.160"></a>
+<span class="sourceLineNo">161</span>            // fam is just "sourceCf"<a name="line.161"></a>
+<span class="sourceLineNo">162</span>            sourceCf = fam;<a name="line.162"></a>
+<span class="sourceLineNo">163</span>        }<a name="line.163"></a>
+<span class="sourceLineNo">164</span>        scan.addFamily(Bytes.toBytes(sourceCf));<a name="line.164"></a>
+<span class="sourceLineNo">165</span>      }<a name="line.165"></a>
+<span class="sourceLineNo">166</span>      Import.configureCfRenaming(job.getConfiguration(), cfRenameMap);<a name="line.166"></a>
+<span class="sourceLineNo">167</span>    }<a name="line.167"></a>
+<span class="sourceLineNo">168</span>    job.setNumReduceTasks(0);<a name="line.168"></a>
+<span class="sourceLineNo">169</span><a name="line.169"></a>
+<span class="sourceLineNo">170</span>    if (bulkload) {<a name="line.170"></a>
+<span class="sourceLineNo">171</span>      initCopyTableMapperReducerJob(job, scan);<a name="line.171"></a>
+<span class="sourceLineNo">172</span><a name="line.172"></a>
+<span class="sourceLineNo">173</span>      // We need to split the inputs by destination tables so that output of Map can be bulk-loaded.<a name="line.173"></a>
+<span class="sourceLineNo">174</span>      TableInputFormat.configureSplitTable(job, TableName.valueOf(dstTableName));<a name="line.174"></a>
+<span class="sourceLineNo">175</span><a name="line.175"></a>
+<span class="sourceLineNo">176</span>      bulkloadDir = generateUniqTempDir(false);<a name="line.176"></a>
+<span class="sourceLineNo">177</span>      LOG.info("HFiles will be stored at " + this.bulkloadDir);<a name="line.177"></a>
+<span class="sourceLineNo">178</span>      HFileOutputFormat2.setOutputPath(job, bulkloadDir);<a name="line.178"></a>
+<span class="sourceLineNo">179</span>      try (Connection conn = ConnectionFactory.createConnection(getConf());<a name="line.179"></a>
+<span class="sourceLineNo">180</span>          Admin admin = conn.getAdmin()) {<a name="line.180"></a>
+<span class="sourceLineNo">181</span>        HFileOutputFormat2.configureIncrementalLoadMap(job,<a name="line.181"></a>
+<span class="sourceLineNo">182</span>          admin.getDescriptor((TableName.valueOf(dstTableName))));<a name="line.182"></a>
+<span class="sourceLineNo">183</span>      }<a name="line.183"></a>
+<span class="sourceLineNo">184</span>    } else {<a name="line.184"></a>
+<span class="sourceLineNo">185</span>      initCopyTableMapperReducerJob(job, scan);<a name="line.185"></a>
+<span class="sourceLineNo">186</span>      TableMapReduceUtil.initTableReducerJob(dstTableName, null, job, null, peerAddress, null,<a name="line.186"></a>
+<span class="sourceLineNo">187</span>        null);<a name="line.187"></a>
+<span class="sourceLineNo">188</span>    }<a name="line.188"></a>
+<span class="sourceLineNo">189</span><a name="line.189"></a>
+<span class="sourceLineNo">190</span>    return job;<a name="line.190"></a>
+<span class="sourceLineNo">191</span>  }<a name="line.191"></a>
+<span class="sourceLineNo">192</span><a name="line.192"></a>
+<span class="sourceLineNo">193</span>  /*<a name="line.193"></a>
+<span class="sourceLineNo">194</span>   * @param errorMsg Error message.  Can be null.<a name="line.194"></a>
+<span class="sourceLineNo">195</span>   */<a name="line.195"></a>
+<span class="sourceLineNo">196</span>  private static void printUsage(final String errorMsg) {<a name="line.196"></a>
+<span class="sourceLineNo">197</span>    if (errorMsg != null &amp;&amp; errorMsg.length() &gt; 0) {<a name="line.197"></a>
+<span class="sourceLineNo">198</span>      System.err.println("ERROR: " + errorMsg);<a name="line.198"></a>
+<span class="sourceLineNo">199</span>    }<a name="line.199"></a>
+<span class="sourceLineNo">200</span>    System.err.println("Usage: CopyTable [general options] [--starttime=X] [--endtime=Y] " +<a name="line.200"></a>
+<span class="sourceLineNo">201</span>        "[--new.name=NEW] [--peer.adr=ADR] &lt;tablename | snapshotName&gt;");<a name="line.201"></a>
+<span class="sourceLineNo">202</span>    System.err.println();<a name="line.202"></a>
+<span class="sourceLineNo">203</span>    System.err.println("Options:");<a name="line.203"></a>
+<span class="sourceLineNo">204</span>    System.err.println(" rs.class     hbase.regionserver.class of the peer cluster");<a name="line.204"></a>
+<span class="sourceLineNo">205</span>    System.err.println("              specify if different from current cluster");<a name="line.205"></a>
+<span class="sourceLineNo">206</span>    System.err.println(" rs.impl      hbase.regionserver.impl of the peer cluster");<a name="line.206"></a>
+<span class="sourceLineNo">207</span>    System.err.println(" startrow     the start row");<a name="line.207"></a>
+<span class="sourceLineNo">208</span>    System.err.println(" stoprow      the stop row");<a name="line.208"></a>
+<span class="sourceLineNo">209</span>    System.err.println(" starttime    beginning of the time range (unixtime in millis)");<a name="line.209"></a>
+<span class="sourceLineNo">210</span>    System.err.println("              without endtime means from starttime to forever");<a name="line.210"></a>
+<span class="sourceLineNo">211</span>    System.err.println(" endtime      end of the time range.  Ignored if no starttime specified.");<a name="line.211"></a>
+<span class="sourceLineNo">212</span>    System.err.println(" versions     number of cell versions to copy");<a name="line.212"></a>
+<span class="sourceLineNo">213</span>    System.err.println(" new.name     new table's name");<a name="line.213"></a>
+<span class="sourceLineNo">214</span>    System.err.println(" peer.adr     Address of the peer cluster given in the format");<a name="line.214"></a>
+<span class="sourceLineNo">215</span>    System.err.println("              hbase.zookeeper.quorum:hbase.zookeeper.client"<a name="line.215"></a>
+<span class="sourceLineNo">216</span>        + ".port:zookeeper.znode.parent");<a name="line.216"></a>
+<span class="sourceLineNo">217</span>    System.err.println(" families     comma-separated list of families to copy");<a name="line.217"></a>
+<span class="sourceLineNo">218</span>    System.err.println("              To copy from cf1 to cf2, give sourceCfName:destCfName. ");<a name="line.218"></a>
+<span class="sourceLineNo">219</span>    System.err.println("              To keep the same name, just give \"cfName\"");<a name="line.219"></a>
+<span class="sourceLineNo">220</span>    System.err.println(" all.cells    also copy delete markers and deleted cells");<a name="line.220"></a>
+<span class="sourceLineNo">221</span>    System.err.println(" bulkload     Write input into HFiles and bulk load to the destination "<a name="line.221"></a>
+<span class="sourceLineNo">222</span>        + "table");<a name="line.222"></a>
+<span class="sourceLineNo">223</span>    System.err.println(" snapshot     Copy the data from snapshot to destination table.");<a name="line.223"></a>
+<span class="sourceLineNo">224</span>    System.err.println();<a name="line.224"></a>
+<span class="sourceLineNo">225</span>    System.err.println("Args:");<a name="line.225"></a>
+<span class="sourceLineNo">226</span>    System.err.println(" tablename    Name of the table to copy");<a name="line.226"></a>
+<span class="sourceLineNo">227</span>    System.err.println();<a name="line.227"></a>
+<span class="sourceLineNo">228</span>    System.err.println("Examples:");<a name="line.228"></a>
+<span class="sourceLineNo">229</span>    System.err.println(" To copy 'TestTable' to a cluster that uses replication for a 1 hour window:");<a name="line.229"></a>
+<span class="sourceLineNo">230</span>    System.err.println(" $ hbase " +<a name="line.230"></a>
+<span class="sourceLineNo">231</span>        "org.apache.hadoop.hbase.mapreduce.CopyTable --starttime=1265875194289 --endtime=1265878794289 " +<a name="line.231"></a>
+<span class="sourceLineNo">232</span>        "--peer.adr=server1,server2,server3:2181:/hbase --families=myOldCf:myNewCf,cf2,cf3 TestTable ");<a name="line.232"></a>
+<span class="sourceLineNo">233</span>    System.err.println(" To copy data from 'sourceTableSnapshot' to 'destTable': ");<a name="line.233"></a>
+<span class="sourceLineNo">234</span>    System.err.println(" $ hbase org.apache.hadoop.hbase.mapreduce.CopyTable "<a name="line.234"></a>
+<span class="sourceLineNo">235</span>        + "--snapshot --new.name=destTable sourceTableSnapshot");<a name="line.235"></a>
+<span class="sourceLineNo">236</span>    System.err.println(" To copy data from 'sourceTableSnapshot' and bulk load to 'destTable': ");<a name="line.236"></a>
+<span class="sourceLineNo">237</span>    System.err.println(" $ hbase org.apache.hadoop.hbase.mapreduce.CopyTable "<a name="line.237"></a>
+<span class="sourceLineNo">238</span>        + "--new.name=destTable --snapshot --bulkload sourceTableSnapshot");<a name="line.238"></a>
+<span class="sourceLineNo">239</span>    System.err.println("For performance consider the following general option:\n"<a name="line.239"></a>
+<span class="sourceLineNo">240</span>        + "  It is recommended that you set the following to &gt;=100. A higher value uses more memory but\n"<a name="line.240"></a>
+<span class="sourceLineNo">241</span>        + "  decreases the round trip time to the server and may increase performance.\n"<a name="line.241"></a>
+<span class="sourceLineNo">242</span>        + "    -Dhbase.client.scanner.caching=100\n"<a name="line.242"></a>
+<span class="sourceLineNo">243</span>        + "  The following should always be set to false, to prevent writing data twice, which may produce \n"<a name="line.243"></a>
+<span class="sourceLineNo">244</span>        + "  inaccurate results.\n"<a name="line.244"></a>
+<span class="sourceLineNo">245</span>        + "    -Dmapreduce.map.speculative=false");<a name="line.245"></a>
+<span class="sourceLineNo">246</span>  }<a name="line.246"></a>
+<span class="sourceLineNo">247</span><a name="line.247"></a>
+<span class="sourceLineNo">248</span>  private boolean doCommandLine(final String[] args) {<a name="line.248"></a>
+<span class="sourceLineNo">249</span>    if (args.length &lt; 1) {<a name="line.249"></a>
+<span class="sourceLineNo">250</span>      printUsage(null);<a name="line.250"></a>
+<span class="sourceLineNo">251</span>      return false;<a name="line.251"></a>
+<span class="sourceLineNo">252</span>    }<a name="line.252"></a>
+<span class="sourceLineNo">253</span>    try {<a name="line.253"></a>
+<span class="sourceLineNo">254</span>      for (int i = 0; i &lt; args.length; i++) {<a name="line.254"></a>
+<span class="sourceLineNo">255</span>        String cmd = args[i];<a name="line.255"></a>
+<span class="sourceLineNo">256</span>        if (cmd.equals("-h") || cmd.startsWith("--h")) {<a name="line.256"></a>
+<span class="sourceLineNo">257</span>          printUsage(null);<a name="line.257"></a>
+<span class="sourceLineNo">258</span>          return false;<a name="line.258"></a>
+<span class="sourceLineNo">259</span>        }<a name="line.259"></a>
+<span class="sourceLineNo">260</span><a name="line.260"></a>
+<span class="sourceLineNo">261</span>        final String startRowArgKey = "--startrow=";<a name="line.261"></a>
+<span class="sourceLineNo">262</span>        if (cmd.startsWith(startRowArgKey)) {<a name="line.262"></a>
+<span class="sourceLineNo">263</span>          startRow = cmd.substring(startRowArgKey.length());<a name="line.263"></a>
+<span class="sourceLineNo">264</span>          continue;<a name="line.264"></a>
+<span class="sourceLineNo">265</span>        }<a name="line.265"></a>
+<span class="sourceLineNo">266</span><a name="line.266"></a>
+<span class="sourceLineNo">267</span>        final String stopRowArgKey = "--stoprow=";<a name="line.267"></a>
+<span class="sourceLineNo">268</span>        if (cmd.startsWith(stopRowArgKey)) {<a name="line.268"></a>
+<span class="sourceLineNo">269</span>          stopRow = cmd.substring(stopRowArgKey.length());<a name="line.269"></a>
+<span class="sourceLineNo">270</span>          continue;<a name="line.270"></a>
+<span class="sourceLineNo">271</span>        }<a name="line.271"></a>
+<span class="sourceLineNo">272</span><a name="line.272"></a>
+<span class="sourceLineNo">273</span>        final String startTimeArgKey = "--starttime=";<a name="line.273"></a>
+<span class="sourceLineNo">274</span>        if (cmd.startsWith(startTimeArgKey)) {<a name="line.274"></a>
+<span class="sourceLineNo">275</span>          startTime = Long.parseLong(cmd.substring(startTimeArgKey.length()));<a name="line.275"></a>
+<span class="sourceLineNo">276</span>          continue;<a name="line.276"></a>
+<span class="sourceLineNo">277</span>        }<a name="line.277"></a>
+<span class="sourceLineNo">278</span><a name="line.278"></a>
+<span class="sourceLineNo">279</span>        final String endTimeArgKey = "--endtime=";<a name="line.279"></a>
+<span class="sourceLineNo">280</span>        if (cmd.startsWith(endTimeArgKey)) {<a name="line.280"></a>
+<span class="sourceLineNo">281</span>          endTime = Long.parseLong(cmd.substring(endTimeArgKey.length()));<a name="line.281"></a>
+<span class="sourceLineNo">282</span>          continue;<a name="line.282"></a>
+<span class="sourceLineNo">283</span>        }<a name="line.283"></a>
+<span class="sourceLineNo">284</span><a name="line.284"></a>
+<span class="sourceLineNo">285</span>        final String batchArgKey = "--batch=";<a name="line.285"></a>
+<span class="sourceLineNo">286</span>        if (cmd.startsWith(batchArgKey)) {<a name="line.286"></a>
+<span class="sourceLineNo">287</span>          batch = Integer.parseInt(cmd.substring(batchArgKey.length()));<a name="line.287"></a>
+<span class="sourceLineNo">288</span>          continue;<a name="line.288"></a>
+<span class="sourceLineNo">289</span>        }<a name="line.289"></a>
+<span class="sourceLineNo">290</span><a name="line.290"></a>
+<span class="sourceLineNo">291</span>        final String cacheRowArgKey = "--cacheRow=";<a name="line.291"></a>
+<span class="sourceLineNo">292</span>        if (cmd.startsWith(cacheRowArgKey)) {<a name="line.292"></a>
+<span class="sourceLineNo">293</span>          cacheRow = Integer.parseInt(cmd.substring(cacheRowArgKey.length()));<a name="line.293"></a>
+<span class="sourceLineNo">294</span>          continue;<a name="line.294"></a>
+<span class="sourceLineNo">295</span>        }<a name="line.295"></a>
+<span class="sourceLineNo">296</span><a name="line.296"></a>
+<span class="sourceLineNo">297</span>        final String versionsArgKey = "--versions=";<a name="line.297"></a>
+<span class="sourceLineNo">298</span>        if (cmd.startsWith(versionsArgKey)) {<a name="line.298"></a>
+<span class="sourceLineNo">299</span>          versions = Integer.parseInt(cmd.substring(versionsArgKey.length()));<a name="line.299"></a>
+<span class="sourceLineNo">300</span>          continue;<a name="line.300"></a>
+<span class="sourceLineNo">301</span>        }<a name="line.301"></a>
+<span class="sourceLineNo">302</span><a name="line.302"></a>
+<span class="sourceLineNo">303</span>        final String newNameArgKey = "--new.name=";<a name="line.303"></a>
+<span class="sourceLineNo">304</span>        if (cmd.startsWith(newNameArgKey)) {<a name="line.304"></a>
+<span class="sourceLineNo">305</span>          dstTableName = cmd.substring(newNameArgKey.length());<a name="line.305"></a>
+<span class="sourceLineNo">306</span>          continue;<a name="line.306"></a>
+<span class="sourceLineNo">307</span>        }<a name="line.307"></a>
+<span class="sourceLineNo">308</span><a name="line.308"></a>
+<span class="sourceLineNo">309</span>        final String peerAdrArgKey = "--peer.adr=";<a name="line.309"></a>
+<span class="sourceLineNo">310</span>        if (cmd.startsWith(peerAdrArgKey)) {<a name="line.310"></a>
+<span class="sourceLineNo">311</span>          peerAddress = cmd.substring(peerAdrArgKey.length());<a name="line.311"></a>
+<span class="sourceLineNo">312</span>          continue;<a name="line.312"></a>
+<span class="sourceLineNo">313</span>        }<a name="line.313"></a>
+<span class="sourceLineNo">314</span><a name="line.314"></a>
+<span class="sourceLineNo">315</span>        final String familiesArgKey = "--families=";<a name="line.315"></a>
+<span class="sourceLineNo">316</span>        if (cmd.startsWith(familiesArgKey)) {<a name="line.316"></a>
+<span class="sourceLineNo">317</span>          families = cmd.substring(familiesArgKey.length());<a name="line.317"></a>
+<span class="sourceLineNo">318</span>          continue;<a name="line.318"></a>
+<span class="sourceLineNo">319</span>        }<a name="line.319"></a>
+<span class="sourceLineNo">320</span><a name="line.320"></a>
+<span class="sourceLineNo">321</span>        if (cmd.startsWith("--all.cells")) {<a name="line.321"></a>
+<span class="sourceLineNo">322</span>          allCells = true;<a name="line.322"></a>
+<span class="sourceLineNo">323</span>          continue;<a name="line.323"></a>
+<span class="sourceLineNo">324</span>        }<a name="line.324"></a>
+<span class="sourceLineNo">325</span><a name="line.325"></a>
+<span class="sourceLineNo">326</span>        if (cmd.startsWith("--bulkload")) {<a name="line.326"></a>
+<span class="sourceLineNo">327</span>          bulkload = true;<a name="line.327"></a>
+<span class="sourceLineNo">328</span>          continue;<a name="line.328"></a>
+<span class="sourceLineNo">329</span>        }<a name="line.329"></a>
+<span class="sourceLineNo">330</span><a name="line.330"></a>
+<span class="sourceLineNo">331</span>        if (cmd.startsWith("--shuffle")) {<a name="line.331"></a>
+<span class="sourceLineNo">332</span>          shuffle = true;<a name="line.332"></a>
+<span class="sourceLineNo">333</span>          continue;<a name="line.333"></a>
+<span class="sourceLineNo">334</span>        }<a name="line.334"></a>
+<span class="sourceLineNo">335</span><a name="line.335"></a>
+<span class="sourceLineNo">336</span>        if(cmd.startsWith("--snapshot")){<a name="line.336"></a>
+<span class="sourceLineNo">337</span>          readingSnapshot = true;<a name="line.337"></a>
+<span class="sourceLineNo">338</span>          continue;<a name="line.338"></a>
+<span class="sourceLineNo">339</span>        }<a name="line.339"></a>
+<span class="sourceLineNo">340</span><a name="line.340"></a>
+<span class="sourceLineNo">341</span>        if (i == args.length - 1) {<a name="line.341"></a>
+<span class="sourceLineNo">342</span>          if (readingSnapshot) {<a name="line.342"></a>
+<span class="sourceLineNo">343</span>            snapshot = cmd;<a name="line.343"></a>
+<span class="sourceLineNo">344</span>          } else {<a name="line.344"></a>
+<span class="sourceLineNo">345</span>            tableName = cmd;<a name="line.345"></a>
+<span class="sourceLineNo">346</span>          }<a name="line.346"></a>
+<span class="sourceLineNo">347</span>        } else {<a name="line.347"></a>
+<span class="sourceLineNo">348</span>          printUsage("Invalid argument '" + cmd + "'");<a name="line.348"></a>
+<span class="sourceLineNo">349</span>          return false;<a name="line.349"></a>
+<span class="sourceLineNo">350</span>        }<a name="line.350"></a>
+<span class="sourceLineNo">351</span>      }<a name="line.351"></a>
+<span class="sourceLineNo">352</span>      if (dstTableName == null &amp;&amp; peerAddress == null) {<a name="line.352"></a>
+<span class="sourceLineNo">353</span>        printUsage("At least a new table name or a peer address must be specified");<a name="line.353"></a>
+<span class="sourceLineNo">354</span>        return false;<a name="line.354"></a>
+<span class="sourceLineNo">355</span>      }<a name="line.355"></a>
+<span class="sourceLineNo">356</span>      if ((endTime != 0) &amp;&amp; (startTime &gt; endTime)) {<a name="line.356"></a>
+<span class="sourceLineNo">357</span>        printUsage("Invalid time range filter: starttime=" + startTime + " &gt;  endtime=" + endTime);<a name="line.357"></a>
+<span class="sourceLineNo">358</span>        return false;<a name="line.358"></a>
+<span class="sourceLineNo">359</span>      }<a name="line.359"></a>
 <span class="sourceLineNo">360</span><a name="line.360"></a>
-<span class="sourceLineNo">361</span>  @Override<a name="line.361"></a>
-<span class="sourceLineNo">362</span>  public int run(String[] args) throws Exception {<a name="line.362"></a>
-<span class="sourceLineNo">363</span>    Job job = createSubmittableJob(args);<a name="line.363"></a>
-<span class="sourceLineNo">364</span>    if (job == null) return 1;<a name="line.364"></a>
-<span class="sourceLineNo">365</span>    if (!job.waitForCompletion(true)) {<a name="line.365"></a>
-<span class="sourceLineNo">366</span>      LOG.info("Map-reduce job failed!");<a name="line.366"></a>
-<span class="sourceLineNo">367</span>      if (bulkload) {<a name="line.367"></a>
-<span class="sourceLineNo">368</span>        LOG.info("Files are not bulkloaded!");<a name="line.368"></a>
+<span class="sourceLineNo">361</span>      if (bulkload &amp;&amp; peerAddress != null) {<a name="line.361"></a>
+<span class="sourceLineNo">362</span>        printUsage("Remote bulkload is not supported!");<a name="line.362"></a>
+<span class="sourceLineNo">363</span>        return false;<a name="line.363"></a>
+<span class="sourceLineNo">364</span>      }<a name="line.364"></a>
+<span class="sourceLineNo">365</span><a name="line.365"></a>
+<span class="sourceLineNo">366</span>      if (readingSnapshot &amp;&amp; peerAddress != null) {<a name="line.366"></a>
+<span class="sourceLineNo">367</span>        printUsage("Loading data from snapshot to remote peer cluster is not supported.");<a name="line.367"></a>
+<span class="sourceLineNo">368</span>        return false;<a name="line.368"></a>
 <span class="sourceLineNo">369</span>      }<a name="line.369"></a>
-<span class="sourceLineNo">370</span>      return 1;<a name="line.370"></a>
-<span class="sourceLineNo">371</span>    }<a name="line.371"></a>
-<span class="sourceLineNo">372</span>    int code = 0;<a name="line.372"></a>
-<span class="sourceLineNo">373</span>    if (bulkload) {<a name="line.373"></a>
-<span class="sourceLineNo">374</span>      code = new LoadIncrementalHFiles(this.getConf())<a name="line.374"></a>
-<span class="sourceLineNo">375</span>          .run(new String[] { this.bulkloadDir.toString(), this.dstTableName });<a name="line.375"></a>
-<span class="sourceLineNo">376</span>      if (code == 0) {<a name="line.376"></a>
-<span class="sourceLineNo">377</span>        // bulkloadDir is deleted only LoadIncrementalHFiles was successful so that one can rerun<a name="line.377"></a>
-<span class="sourceLineNo">378</span>        // LoadIncrementalHFiles.<a name="line.378"></a>
-<span class="sourceLineNo">379</span>        FileSystem fs = FSUtils.getCurrentFileSystem(getConf());<a name="line.379"></a>
-<span class="sourceLineNo">380</span>        if (!fs.delete(this.bulkloadDir, true)) {<a name="line.380"></a>
-<span class="sourceLineNo">381</span>          LOG.error("Deleting folder " + bulkloadDir + " failed!");<a name="line.381"></a>
-<span class="sourceLineNo">382</span>          code = 1;<a name="line.382"></a>
-<span class="sourceLineNo">383</span>        }<a name="line.383"></a>
-<span class="sourceLineNo">384</span>      }<a name="line.384"></a>
-<span class="sourceLineNo">385</span>    }<a name="line.385"></a>
-<span class="sourceLineNo">386</span>    return code;<a name="line.386"></a>
-<span class="sourceLineNo">387</span>  }<a name="line.387"></a>
-<span class="sourceLineNo">388</span>}<a name="line.388"></a>
+<span class="sourceLineNo">370</span><a name="line.370"></a>
+<span class="sourceLineNo">371</span>      if (readingSnapshot &amp;&amp; dstTableName == null) {<a name="line.371"></a>
+<span class="sourceLineNo">372</span>        printUsage("The --new.name=&lt;table&gt; for destination table should be "<a name="line.372"></a>
+<span class="sourceLineNo">373</span>            + "provided when copying data from snapshot .");<a name="line.373"></a>
+<span class="sourceLineNo">374</span>        return false;<a name="line.374"></a>
+<span class="sourceLineNo">375</span>      }<a name="line.375"></a>
+<span class="sourceLineNo">376</span><a name="line.376"></a>
+<span class="sourceLineNo">377</span>      if (readingSnapshot &amp;&amp; snapshot == null) {<a name="line.377"></a>
+<span class="sourceLineNo">378</span>        printUsage("Snapshot shouldn't be null when --snapshot is enabled.");<a name="line.378"></a>
+<span class="sourceLineNo">379</span>        return false;<a name="line.379"></a>
+<span class="sourceLineNo">380</span>      }<a name="line.380"></a>
+<span class="sourceLineNo">381</span><a name="line.381"></a>
+<span class="sourceLineNo">382</span>      // set dstTableName if necessary<a name="line.382"></a>
+<span class="sourceLineNo">383</span>      if (dstTableName == null) {<a name="line.383"></a>
+<span class="sourceLineNo">384</span>        dstTableName = tableName;<a name="line.384"></a>
+<span class="sourceLineNo">385</span>      }<a name="line.385"></a>
+<span class="sourceLineNo">386</span>    } catch (Exception e) {<a name="line.386"></a>
+<span class="sourceLineNo">387</span>      LOG.error("Failed to parse commandLine arguments", e);<a name="line.387"></a>
+<span class="sourceLineNo">388</span>      printUsage("Can't start because " + e.getMessage());<a name="line.388"></a>
+<span class="sourceLineNo">389</span>      return false;<a name="line.389"></a>
+<span class="sourceLineNo">390</span>    }<a name="line.390"></a>
+<span class="sourceLineNo">391</span>    return true;<a name="line.391"></a>
+<span class="sourceLineNo">392</span>  }<a name="line.392"></a>
+<span class="sourceLineNo">393</span><a name="line.393"></a>
+<span class="sourceLineNo">394</span>  /**<a name="line.394"></a>
+<span class="sourceLineNo">395</span>   * Main entry point.<a name="line.395"></a>
+<span class="sourceLineNo">396</span>   *<a name="line.396"></a>
+<span class="sourceLineNo">397</span>   * @param args  The command line parameters.<a name="line.397"></a>
+<span class="sourceLineNo">398</span>   * @throws Exception When running the job fails.<a name="line.398"></a>
+<span class="sourceLineNo">399</span>   */<a name="line.399"></a>
+<span class="sourceLineNo">400</span>  public static void main(String[] args) throws Exception {<a name="line.400"></a>
+<span class="sourceLineNo">401</span>    int ret = ToolRunner.run(HBaseConfiguration.create(), new CopyTable(), args);<a name="line.401"></a>
+<span class="sourceLineNo">402</span>    System.exit(ret);<a name="line.402"></a>
+<span class="sourceLineNo">403</span>  }<a name="line.403"></a>
+<span class="sourceLineNo">404</span><a name="line.404"></a>
+<span class="sourceLineNo">405</span>  @Override<a name="line.405"></a>
+<span class="sourceLineNo">406</span>  public int run(String[] args) throws Exception {<a name="line.406"></a>
+<span class="sourceLineNo">407</span>    Job job = createSubmittableJob(args);<a name="line.407"></a>
+<span class="sourceLineNo">408</span>    if (job == null) return 1;<a name="line.408"></a>
+<span class="sourceLineNo">409</span>    if (!job.waitForCompletion(true)) {<a name="line.409"></a>
+<span class="sourceLineNo">410</span>      LOG.info("Map-reduce job failed!");<a name="line.410"></a>
+<span class="sourceLineNo">411</span>      if (bulkload) {<a name="line.411"></a>
+<span class="sourceLineNo">412</span>        LOG.info("Files are not bulkloaded!");<a name="line.412"></a>
+<span class="sourceLineNo">413</span>      }<a name="line.413"></a>
+<span class="sourceLineNo">414</span>      return 1;<a name="line.414"></a>
+<span class="sourceLineNo">415</span>    }<a name="line.415"></a>
+<span class="sourceLineNo">416</span>    int code = 0;<a name="line.416"></a>
+<span class="sourceLineNo">417</span>    if (bulkload) {<a name="line.417"></a>
+<span class="sourceLineNo">418</span>      LOG.info("Trying to bulk load data to destination table: " + dstTableName);<a name="line.418"></a>
+<span class="sourceLineNo">419</span>      LOG.info("command: ./bin/hbase org.apache.hadoop.hbase.tool.LoadIncrementalHFiles {} {}",<a name="line.419"></a>
+<span class="sourceLineNo">420</span>        this.bulkloadDir.toString(), this.dstTableName);<a name="line.420"></a>
+<span class="sourceLineNo">421</span>      code = new LoadIncrementalHFiles(this.getConf())<a name="line.421"></a>
+<span class="sourceLineNo">422</span>          .run(new String[] { this.bulkloadDir.toString(), this.dstTableName });<a name="line.422"></a>
+<span class="sourceLineNo">423</span>      if (code == 0) {<a name="line.423"></a>
+<span class="sourceLineNo">424</span>        // bulkloadDir is deleted only LoadIncrementalHFiles was successful so that one can rerun<a name="line.424"></a>
+<span class="sourceLineNo">425</span>        // LoadIncrementalHFiles.<a name="line.425"></a>
+<span class="sourceLineNo">426</span>        FileSystem fs = FSUtils.getCurrentFileSystem(getConf());<a name="line.426"></a>
+<span class="sourceLineNo">427</span>        if (!fs.delete(this.bulkloadDir, true)) {<a name="line.427"></a>
+<span class="sourceLineNo">428</span>          LOG.error("Deleting folder " + bulkloadDir + " failed!");<a name="line.428"></a>
+<span class="sourceLineNo">429</span>          code = 1;<a name="line.429"></a>
+<span class="sourceLineNo">430</span>        }<a name="line.430"></a>
+<span class="sourceLineNo">431</span>      }<a name="line.431"></a>
+<span class="sourceLineNo">432</span>    }<a name="line.432"></a>
+<span class="sourceLineNo">433</span>    return code;<a name="line.433"></a>
+<span class="sourceLineNo">434</span>  }<a name="line.434"></a>
+<span class="sourceLineNo">435</span>}<a name="line.435"></a>
 
 
 

http://git-wip-us.apache.org/repos/asf/hbase-site/blob/09ea0d5f/book.html
----------------------------------------------------------------------
diff --git a/book.html b/book.html
index af029d9..7663020 100644
--- a/book.html
+++ b/book.html
@@ -17825,19 +17825,12 @@ Using bulk load will use less CPU and network resources than simply using the HB
 </div>
 </div>
 <div class="sect2">
-<h3 id="arch.bulk.load.limitations"><a class="anchor" href="#arch.bulk.load.limitations"></a>73.2. Bulk Load Limitations</h3>
-<div class="paragraph">
-<p>As bulk loading bypasses the write path, the WAL doesn&#8217;t get written to as part of the process.
-Replication works by reading the WAL files so it won&#8217;t see the bulk loaded data – and the same goes for the edits that use <code>Put.setDurability(SKIP_WAL)</code>. One way to handle that is to ship the raw files or the HFiles to the other cluster and do the other processing there.</p>
-</div>
-</div>
-<div class="sect2">
-<h3 id="arch.bulk.load.arch"><a class="anchor" href="#arch.bulk.load.arch"></a>73.3. Bulk Load Architecture</h3>
+<h3 id="arch.bulk.load.arch"><a class="anchor" href="#arch.bulk.load.arch"></a>73.2. Bulk Load Architecture</h3>
 <div class="paragraph">
 <p>The HBase bulk load process consists of two main steps.</p>
 </div>
 <div class="sect3">
-<h4 id="arch.bulk.load.prep"><a class="anchor" href="#arch.bulk.load.prep"></a>73.3.1. Preparing data via a MapReduce job</h4>
+<h4 id="arch.bulk.load.prep"><a class="anchor" href="#arch.bulk.load.prep"></a>73.2.1. Preparing data via a MapReduce job</h4>
 <div class="paragraph">
 <p>The first step of a bulk load is to generate HBase data files (StoreFiles) from a MapReduce job using <code>HFileOutputFormat2</code>.
 This output format writes out data in HBase&#8217;s internal storage format so that they can be later loaded very efficiently into the cluster.</p>
@@ -17851,7 +17844,7 @@ In order to do this, jobs whose output will be bulk loaded into HBase use Hadoop
 </div>
 </div>
 <div class="sect3">
-<h4 id="arch.bulk.load.complete"><a class="anchor" href="#arch.bulk.load.complete"></a>73.3.2. Completing the data load</h4>
+<h4 id="arch.bulk.load.complete"><a class="anchor" href="#arch.bulk.load.complete"></a>73.2.2. Completing the data load</h4>
 <div class="paragraph">
 <p>After a data import has been prepared, either by using the <code>importtsv</code> tool with the &#8220;importtsv.bulk.output&#8221; option or by some other MapReduce job using the <code>HFileOutputFormat</code>, the <code>completebulkload</code> tool is used to import the data into the running cluster.
 This command line tool iterates through the prepared data files, and for each one determines the region the file belongs to.
@@ -17884,7 +17877,7 @@ If the target table does not already exist in HBase, this tool will create the t
 </div>
 </div>
 <div class="sect2">
-<h3 id="arch.bulk.load.also"><a class="anchor" href="#arch.bulk.load.also"></a>73.4. See Also</h3>
+<h3 id="arch.bulk.load.also"><a class="anchor" href="#arch.bulk.load.also"></a>73.3. See Also</h3>
 <div class="paragraph">
 <p>For more information about the referenced utilities, see <a href="#importtsv">ImportTsv</a> and  <a href="#completebulkload">CompleteBulkLoad</a>.</p>
 </div>
@@ -17893,7 +17886,7 @@ If the target table does not already exist in HBase, this tool will create the t
 </div>
 </div>
 <div class="sect2">
-<h3 id="arch.bulk.load.adv"><a class="anchor" href="#arch.bulk.load.adv"></a>73.5. Advanced Usage</h3>
+<h3 id="arch.bulk.load.adv"><a class="anchor" href="#arch.bulk.load.adv"></a>73.4. Advanced Usage</h3>
 <div class="paragraph">
 <p>Although the <code>importtsv</code> tool is useful in many cases, advanced users may want to generate data programmatically, or import data from other formats.
 To get started doing so, dig into <code>ImportTsv.java</code> and check the JavaDoc for HFileOutputFormat.</p>
@@ -17903,6 +17896,53 @@ To get started doing so, dig into <code>ImportTsv.java</code> and check the Java
 See the <code>LoadIncrementalHFiles</code> class for more information.</p>
 </div>
 </div>
+<div class="sect2">
+<h3 id="arch.bulk.load.replication"><a class="anchor" href="#arch.bulk.load.replication"></a>73.5. Bulk Loading Replication</h3>
+<div class="paragraph">
+<p>HBASE-13153 adds replication support for bulk loaded HFiles, available since HBase 1.3/2.0. This feature is enabled by setting <code>hbase.replication.bulkload.enabled</code> to <code>true</code> (default is <code>false</code>).
+You also need to copy the source cluster configuration files to the destination cluster.</p>
+</div>
+<div class="paragraph">
+<p>Additional configurations are required too:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p><code>hbase.replication.source.fs.conf.provider</code></p>
+<div class="paragraph">
+<p>This defines the class which loads the source cluster file system client configuration in the destination cluster. This should be configured for all the RS in the destination cluster. Default is <code>org.apache.hadoop.hbase.replication.regionserver.DefaultSourceFSConfigurationProvider</code>.</p>
+</div>
+</li>
+<li>
+<p><code>hbase.replication.conf.dir</code></p>
+<div class="paragraph">
+<p>This represents the base directory where the file system client configurations of the source cluster are copied to the destination cluster. This should be configured for all the RS in the destination cluster. Default is <code>$HBASE_CONF_DIR</code>.</p>
+</div>
+</li>
+<li>
+<p><code>hbase.replication.cluster.id</code></p>
+<div class="paragraph">
+<p>This configuration is required in the cluster where replication for bulk loaded data is enabled. A source cluster is uniquely identified by the destination cluster using this id. This should be configured for all the RS in the source cluster configuration file for all the RS.</p>
+</div>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>For example: If source cluster FS client configurations are copied to the destination cluster under directory <code>/home/user/dc1/</code>, then <code>hbase.replication.cluster.id</code> should be configured as <code>dc1</code> and <code>hbase.replication.conf.dir</code> as <code>/home/user</code>.</p>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<code>DefaultSourceFSConfigurationProvider</code> supports only <code>xml</code> type files. It loads source cluster FS client configuration only once, so if source cluster FS client configuration files are updated, every peer(s) cluster RS must be restarted to reload the configuration.
+</td>
+</tr>
+</table>
+</div>
+</div>
 </div>
 </div>
 <div class="sect1">
@@ -41371,7 +41411,7 @@ org/apache/hadoop/hbase/security/access/AccessControlClient.revoke:(Lorg/apache/
 <div id="footer">
 <div id="footer-text">
 Version 3.0.0-SNAPSHOT<br>
-Last updated 2018-12-26 14:32:40 UTC
+Last updated 2018-12-27 14:32:59 UTC
 </div>
 </div>
 </body>

http://git-wip-us.apache.org/repos/asf/hbase-site/blob/09ea0d5f/bulk-loads.html
----------------------------------------------------------------------
diff --git a/bulk-loads.html b/bulk-loads.html
index 2a9316d..9dd66d8 100644
--- a/bulk-loads.html
+++ b/bulk-loads.html
@@ -7,7 +7,7 @@
   <head>
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <meta name="Date-Revision-yyyymmdd" content="20181226" />
+    <meta name="Date-Revision-yyyymmdd" content="20181227" />
     <meta http-equiv="Content-Language" content="en" />
     <title>Apache HBase &#x2013;  
       Bulk Loads in Apache HBase (TM)
@@ -316,7 +316,7 @@ under the License. -->
                         <a href="https://www.apache.org/">The Apache Software Foundation</a>.
             All rights reserved.      
                     
-                  <li id="publishDate" class="pull-right">Last Published: 2018-12-26</li>
+                  <li id="publishDate" class="pull-right">Last Published: 2018-12-27</li>
             </p>
                 </div>