001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client;
019
020import static org.junit.Assert.assertNotEquals;
021import static org.junit.Assert.assertTrue;
022
023import java.io.IOException;
024import java.util.List;
025import org.apache.hadoop.hbase.Cell;
026import org.apache.hadoop.hbase.CellBuilderFactory;
027import org.apache.hadoop.hbase.CellBuilderType;
028import org.apache.hadoop.hbase.CellUtil;
029import org.apache.hadoop.hbase.ExtendedCell;
030import org.apache.hadoop.hbase.HBaseClassTestRule;
031import org.apache.hadoop.hbase.PrivateCellUtil;
032import org.apache.hadoop.hbase.io.TimeRange;
033import org.apache.hadoop.hbase.testclassification.ClientTests;
034import org.apache.hadoop.hbase.testclassification.SmallTests;
035import org.apache.hadoop.hbase.util.Bytes;
036import org.junit.Assert;
037import org.junit.ClassRule;
038import org.junit.Test;
039import org.junit.experimental.categories.Category;
040
041@Category({ SmallTests.class, ClientTests.class })
042public class TestMutation {
043
044  @ClassRule
045  public static final HBaseClassTestRule CLASS_RULE =
046    HBaseClassTestRule.forClass(TestMutation.class);
047
048  @Test
049  public void testAppendCopyConstructor() throws IOException {
050    Append origin = new Append(Bytes.toBytes("ROW-01"));
051    origin.setPriority(100);
052    byte[] family = Bytes.toBytes("CF-01");
053
054    origin.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY).setRow(origin.getRow())
055      .setFamily(family).setQualifier(Bytes.toBytes("q")).setType(Cell.Type.Put)
056      .setValue(Bytes.toBytes(100)).build());
057    origin.addColumn(family, Bytes.toBytes("q0"), Bytes.toBytes("value"));
058    origin.setTimeRange(100, 1000);
059    Append clone = new Append(origin);
060    assertEquals(origin, clone);
061    origin.addColumn(family, Bytes.toBytes("q1"), Bytes.toBytes("value"));
062
063    // They should have different cell lists
064    assertNotEquals(origin.getCellList(family), clone.getCellList(family));
065  }
066
067  @Test
068  public void testIncrementCopyConstructor() throws IOException {
069    Increment origin = new Increment(Bytes.toBytes("ROW-01"));
070    origin.setPriority(100);
071    byte[] family = Bytes.toBytes("CF-01");
072
073    origin.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY).setRow(origin.getRow())
074      .setFamily(family).setQualifier(Bytes.toBytes("q")).setType(Cell.Type.Put)
075      .setValue(Bytes.toBytes(100)).build());
076    origin.addColumn(family, Bytes.toBytes("q0"), 4);
077    origin.setTimeRange(100, 1000);
078    Increment clone = new Increment(origin);
079    assertEquals(origin, clone);
080    origin.addColumn(family, Bytes.toBytes("q1"), 3);
081
082    // They should have different cell lists
083    assertNotEquals(origin.getCellList(family), clone.getCellList(family));
084  }
085
086  @Test
087  public void testDeleteCopyConstructor() throws IOException {
088    Delete origin = new Delete(Bytes.toBytes("ROW-01"));
089    origin.setPriority(100);
090    byte[] family = Bytes.toBytes("CF-01");
091
092    origin.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY).setRow(origin.getRow())
093      .setFamily(family).setQualifier(Bytes.toBytes("q")).setType(Cell.Type.Delete).build());
094    origin.addColumn(family, Bytes.toBytes("q0"));
095    origin.addColumns(family, Bytes.toBytes("q1"));
096    origin.addFamily(family);
097    origin.addColumns(family, Bytes.toBytes("q2"), 100);
098    origin.addFamilyVersion(family, 1000);
099    Delete clone = new Delete(origin);
100    assertEquals(origin, clone);
101    origin.addColumn(family, Bytes.toBytes("q3"));
102
103    // They should have different cell lists
104    assertNotEquals(origin.getCellList(family), clone.getCellList(family));
105  }
106
107  @Test
108  public void testPutCopyConstructor() throws IOException {
109    Put origin = new Put(Bytes.toBytes("ROW-01"));
110    origin.setPriority(100);
111    byte[] family = Bytes.toBytes("CF-01");
112
113    origin.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY).setRow(origin.getRow())
114      .setFamily(family).setQualifier(Bytes.toBytes("q")).setType(Cell.Type.Put)
115      .setValue(Bytes.toBytes("value")).build());
116    origin.addColumn(family, Bytes.toBytes("q0"), Bytes.toBytes("V-01"));
117    origin.addColumn(family, Bytes.toBytes("q1"), 100, Bytes.toBytes("V-01"));
118    Put clone = new Put(origin);
119    assertEquals(origin, clone);
120    origin.addColumn(family, Bytes.toBytes("q2"), Bytes.toBytes("V-02"));
121
122    // They should have different cell lists
123    assertNotEquals(origin.getCellList(family), clone.getCellList(family));
124  }
125
126  private void assertEquals(Mutation origin, Mutation clone) {
127    Assert.assertEquals(origin.getFamilyCellMap().size(), clone.getFamilyCellMap().size());
128    for (byte[] family : origin.getFamilyCellMap().keySet()) {
129      List<ExtendedCell> originCells = origin.getCellList(family);
130      List<ExtendedCell> cloneCells = clone.getCellList(family);
131      Assert.assertEquals(originCells.size(), cloneCells.size());
132      for (int i = 0; i != cloneCells.size(); ++i) {
133        ExtendedCell originCell = originCells.get(i);
134        ExtendedCell cloneCell = cloneCells.get(i);
135        assertTrue(PrivateCellUtil.equals(originCell, cloneCell));
136        assertTrue(CellUtil.matchingValue(originCell, cloneCell));
137      }
138    }
139    Assert.assertEquals(origin.getAttributesMap().size(), clone.getAttributesMap().size());
140    for (String name : origin.getAttributesMap().keySet()) {
141      byte[] originValue = origin.getAttributesMap().get(name);
142      byte[] cloneValue = clone.getAttributesMap().get(name);
143      assertTrue(Bytes.equals(originValue, cloneValue));
144    }
145    Assert.assertEquals(origin.getTimestamp(), clone.getTimestamp());
146    Assert.assertEquals(origin.getPriority(), clone.getPriority());
147    if (origin instanceof Append) {
148      assertEquals(((Append) origin).getTimeRange(), ((Append) clone).getTimeRange());
149    }
150    if (origin instanceof Increment) {
151      assertEquals(((Increment) origin).getTimeRange(), ((Increment) clone).getTimeRange());
152    }
153  }
154
155  private static void assertEquals(TimeRange origin, TimeRange clone) {
156    Assert.assertEquals(origin.getMin(), clone.getMin());
157    Assert.assertEquals(origin.getMax(), clone.getMax());
158  }
159
160  // HBASE-14881
161  @Test
162  public void testRowIsImmutableOrNot() {
163    byte[] rowKey = Bytes.toBytes("immutable");
164
165    // Test when row key is immutable
166    Put putRowIsImmutable = new Put(rowKey, true);
167    assertTrue(rowKey == putRowIsImmutable.getRow()); // No local copy is made
168
169    // Test when row key is not immutable
170    Put putRowIsNotImmutable = new Put(rowKey, 1000L, false);
171    assertTrue(rowKey != putRowIsNotImmutable.getRow()); // A local copy is made
172  }
173
174  // HBASE-14882
175  @Test
176  public void testAddImmutableToPut() throws IOException {
177    byte[] row = Bytes.toBytes("immutable-row");
178    byte[] family = Bytes.toBytes("immutable-family");
179
180    byte[] qualifier0 = Bytes.toBytes("immutable-qualifier-0");
181    byte[] value0 = Bytes.toBytes("immutable-value-0");
182
183    byte[] qualifier1 = Bytes.toBytes("immutable-qualifier-1");
184    byte[] value1 = Bytes.toBytes("immutable-value-1");
185    long ts1 = 5000L;
186
187    // "true" indicates that the input row is immutable
188    Put put = new Put(row, true);
189    put
190      .add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY).setRow(row).setFamily(family)
191        .setQualifier(qualifier0).setTimestamp(put.getTimestamp()).setType(Cell.Type.Put)
192        .setValue(value0).build())
193      .add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY).setRow(row).setFamily(family)
194        .setQualifier(qualifier1).setTimestamp(ts1).setType(Cell.Type.Put).setValue(value1)
195        .build());
196
197    // Verify the cell of family:qualifier0
198    Cell cell0 = put.get(family, qualifier0).get(0);
199
200    // Verify no local copy is made for family, qualifier or value
201    assertTrue(cell0.getFamilyArray() == family);
202    assertTrue(cell0.getQualifierArray() == qualifier0);
203    assertTrue(cell0.getValueArray() == value0);
204
205    // Verify timestamp
206    assertTrue(cell0.getTimestamp() == put.getTimestamp());
207
208    // Verify the cell of family:qualifier1
209    Cell cell1 = put.get(family, qualifier1).get(0);
210
211    // Verify no local copy is made for family, qualifier or value
212    assertTrue(cell1.getFamilyArray() == family);
213    assertTrue(cell1.getQualifierArray() == qualifier1);
214    assertTrue(cell1.getValueArray() == value1);
215
216    // Verify timestamp
217    assertTrue(cell1.getTimestamp() == ts1);
218  }
219}