HBASE-14881 Provide a Put API that uses the provided row without coping
(Xiang Li)
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Put.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Put.java
index 6b06875..dbaf3a7 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Put.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Put.java
@@ -117,6 +117,43 @@
   }
 
   /**
+   * Create a Put operation for an immutable row key.
+   *
+   * @param row row key
+   * @param rowIsImmutable whether the input row is immutable.
+   *                       Set to true if the caller can guarantee that
+   *                       the row will not be changed for the Put duration.
+   */
+  public Put(byte [] row, boolean rowIsImmutable) {
+    this(row, HConstants.LATEST_TIMESTAMP, rowIsImmutable);
+  }
+
+  /**
+   * Create a Put operation for an immutable row key, using a given timestamp.
+   *
+   * @param row row key
+   * @param ts timestamp
+   * @param rowIsImmutable whether the input row is immutable.
+   *                       Set to true if the caller can guarantee that
+   *                       the row will not be changed for the Put duration.
+   */
+  public Put(byte[] row, long ts, boolean rowIsImmutable) {
+    // Check and set timestamp
+    if (ts < 0) {
+      throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
+    }
+    this.ts = ts;
+
+    // Deal with row according to rowIsImmutable
+    checkRow(row);
+    if (rowIsImmutable) {  // Row is immutable
+      this.row = row;  // Do not make a local copy, but point to the provided byte array directly
+    } else {  // Row is not immutable
+      this.row = Bytes.copy(row, 0, row.length);  // Make a local copy
+    }
+  }
+
+  /**
    * Copy constructor.  Creates a Put operation cloned from the specified Put.
    * @param putToCopy put to copy
    */
diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestPut.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestPut.java
index 3a877dc..8603fe1 100644
--- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestPut.java
+++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestPut.java
@@ -23,6 +23,8 @@
 import org.junit.Test;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
 public class TestPut {
   @Test
   public void testCopyConstructor() {
@@ -40,4 +42,18 @@
     assertNotEquals(origin.getCellList(family), clone.getCellList(family));
 
   }
+
+  // HBASE-14881
+  @Test
+  public void testRowIsImmutableOrNot() {
+    byte[] rowKey = Bytes.toBytes("immutable");
+
+    // Test when row key is immutable
+    Put putRowIsImmutable = new Put(rowKey, true);
+    assertTrue(rowKey == putRowIsImmutable.getRow());  // No local copy is made
+
+    // Test when row key is not immutable
+    Put putRowIsNotImmutable = new Put(rowKey, 1000L, false);
+    assertTrue(rowKey != putRowIsNotImmutable.getRow());  // A local copy is made
+  }
 }