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.Cell.Type;
027import org.apache.hadoop.hbase.CellBuilderFactory;
028import org.apache.hadoop.hbase.CellBuilderType;
029import org.apache.hadoop.hbase.CellUtil;
030import org.apache.hadoop.hbase.HBaseClassTestRule;
031import org.apache.hadoop.hbase.io.TimeRange;
032import org.apache.hadoop.hbase.testclassification.ClientTests;
033import org.apache.hadoop.hbase.testclassification.SmallTests;
034import org.apache.hadoop.hbase.util.Bytes;
035import org.junit.Assert;
036import org.junit.ClassRule;
037import org.junit.Test;
038import org.junit.experimental.categories.Category;
039
040@Category({ SmallTests.class, ClientTests.class })
041public class TestMutation {
042
043  @ClassRule
044  public static final HBaseClassTestRule CLASS_RULE =
045      HBaseClassTestRule.forClass(TestMutation.class);
046
047  @Test
048  public void testAppendCopyConstructor() throws IOException {
049    Append origin = new Append(Bytes.toBytes("ROW-01"));
050    origin.setPriority(100);
051    byte[] family = Bytes.toBytes("CF-01");
052
053    origin.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
054      .setRow(origin.getRow())
055      .setFamily(family)
056      .setQualifier(Bytes.toBytes("q"))
057      .setType(Type.Put)
058      .setValue(Bytes.toBytes(100))
059      .build());
060    origin.addColumn(family, Bytes.toBytes("q0"), Bytes.toBytes("value"));
061    origin.setTimeRange(100, 1000);
062    Append clone = new Append(origin);
063    assertEquals(origin, clone);
064    origin.addColumn(family, Bytes.toBytes("q1"), Bytes.toBytes("value"));
065
066    //They should have different cell lists
067    assertNotEquals(origin.getCellList(family), clone.getCellList(family));
068  }
069
070  @Test
071  public void testIncrementCopyConstructor() throws IOException {
072    Increment origin = new Increment(Bytes.toBytes("ROW-01"));
073    origin.setPriority(100);
074    byte[] family = Bytes.toBytes("CF-01");
075
076    origin.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
077      .setRow(origin.getRow())
078      .setFamily(family)
079      .setQualifier(Bytes.toBytes("q"))
080      .setType(Cell.Type.Put)
081      .setValue(Bytes.toBytes(100))
082      .build());
083    origin.addColumn(family, Bytes.toBytes("q0"), 4);
084    origin.setTimeRange(100, 1000);
085    Increment clone = new Increment(origin);
086    assertEquals(origin, clone);
087    origin.addColumn(family, Bytes.toBytes("q1"), 3);
088
089    //They should have different cell lists
090    assertNotEquals(origin.getCellList(family), clone.getCellList(family));
091  }
092
093  @Test
094  public void testDeleteCopyConstructor() throws IOException {
095    Delete origin = new Delete(Bytes.toBytes("ROW-01"));
096    origin.setPriority(100);
097    byte[] family = Bytes.toBytes("CF-01");
098
099    origin.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
100      .setRow(origin.getRow())
101      .setFamily(family)
102      .setQualifier(Bytes.toBytes("q"))
103      .setType(Type.Delete)
104      .build());
105    origin.addColumn(family, Bytes.toBytes("q0"));
106    origin.addColumns(family, Bytes.toBytes("q1"));
107    origin.addFamily(family);
108    origin.addColumns(family, Bytes.toBytes("q2"), 100);
109    origin.addFamilyVersion(family, 1000);
110    Delete clone = new Delete(origin);
111    assertEquals(origin, clone);
112    origin.addColumn(family, Bytes.toBytes("q3"));
113
114    //They should have different cell lists
115    assertNotEquals(origin.getCellList(family), clone.getCellList(family));
116  }
117
118  @Test
119  public void testPutCopyConstructor() throws IOException {
120    Put origin = new Put(Bytes.toBytes("ROW-01"));
121    origin.setPriority(100);
122    byte[] family = Bytes.toBytes("CF-01");
123
124    origin.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
125      .setRow(origin.getRow())
126      .setFamily(family)
127      .setQualifier(Bytes.toBytes("q"))
128      .setType(Cell.Type.Put)
129      .setValue(Bytes.toBytes("value"))
130      .build());
131    origin.addColumn(family, Bytes.toBytes("q0"), Bytes.toBytes("V-01"));
132    origin.addColumn(family, Bytes.toBytes("q1"), 100, Bytes.toBytes("V-01"));
133    Put clone = new Put(origin);
134    assertEquals(origin, clone);
135    origin.addColumn(family, Bytes.toBytes("q2"), Bytes.toBytes("V-02"));
136
137    //They should have different cell lists
138    assertNotEquals(origin.getCellList(family), clone.getCellList(family));
139  }
140
141  private void assertEquals(Mutation origin, Mutation clone) {
142    Assert.assertEquals(origin.getFamilyCellMap().size(), clone.getFamilyCellMap().size());
143    for (byte[] family : origin.getFamilyCellMap().keySet()) {
144      List<Cell> originCells = origin.getCellList(family);
145      List<Cell> cloneCells = clone.getCellList(family);
146      Assert.assertEquals(originCells.size(), cloneCells.size());
147      for (int i = 0; i != cloneCells.size(); ++i) {
148        Cell originCell = originCells.get(i);
149        Cell cloneCell = cloneCells.get(i);
150        assertTrue(CellUtil.equals(originCell, cloneCell));
151        assertTrue(CellUtil.matchingValue(originCell, cloneCell));
152      }
153    }
154    Assert.assertEquals(origin.getAttributesMap().size(), clone.getAttributesMap().size());
155    for (String name : origin.getAttributesMap().keySet()) {
156      byte[] originValue = origin.getAttributesMap().get(name);
157      byte[] cloneValue = clone.getAttributesMap().get(name);
158      assertTrue(Bytes.equals(originValue, cloneValue));
159    }
160    Assert.assertEquals(origin.getTimestamp(), clone.getTimestamp());
161    Assert.assertEquals(origin.getPriority(), clone.getPriority());
162    if (origin instanceof Append) {
163      assertEquals(((Append)origin).getTimeRange(), ((Append)clone).getTimeRange());
164    }
165    if (origin instanceof Increment) {
166      assertEquals(((Increment)origin).getTimeRange(), ((Increment)clone).getTimeRange());
167    }
168  }
169
170  private static void assertEquals(TimeRange origin, TimeRange clone) {
171    Assert.assertEquals(origin.getMin(), clone.getMin());
172    Assert.assertEquals(origin.getMax(), clone.getMax());
173  }
174
175  // HBASE-14881
176  @Test
177  public void testRowIsImmutableOrNot() {
178    byte[] rowKey = Bytes.toBytes("immutable");
179
180    // Test when row key is immutable
181    Put putRowIsImmutable = new Put(rowKey, true);
182    assertTrue(rowKey == putRowIsImmutable.getRow());  // No local copy is made
183
184    // Test when row key is not immutable
185    Put putRowIsNotImmutable = new Put(rowKey, 1000L, false);
186    assertTrue(rowKey != putRowIsNotImmutable.getRow());  // A local copy is made
187  }
188
189  // HBASE-14882
190  @Test
191  public void testAddImmutableToPut() throws IOException {
192    byte[] row        = Bytes.toBytes("immutable-row");
193    byte[] family     = Bytes.toBytes("immutable-family");
194
195    byte[] qualifier0 = Bytes.toBytes("immutable-qualifier-0");
196    byte[] value0     = Bytes.toBytes("immutable-value-0");
197
198    byte[] qualifier1 = Bytes.toBytes("immutable-qualifier-1");
199    byte[] value1     = Bytes.toBytes("immutable-value-1");
200    long   ts1        = 5000L;
201
202    // "true" indicates that the input row is immutable
203    Put put = new Put(row, true);
204    put.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
205            .setRow(row)
206            .setFamily(family)
207            .setQualifier(qualifier0)
208            .setTimestamp(put.getTimestamp())
209            .setType(Type.Put)
210            .setValue(value0)
211            .build())
212        .add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
213            .setRow(row)
214            .setFamily(family)
215            .setQualifier(qualifier1)
216            .setTimestamp(ts1)
217            .setType(Type.Put)
218            .setValue(value1)
219            .build());
220
221    // Verify the cell of family:qualifier0
222    Cell cell0 = put.get(family, qualifier0).get(0);
223
224    // Verify no local copy is made for family, qualifier or value
225    assertTrue(cell0.getFamilyArray()    == family);
226    assertTrue(cell0.getQualifierArray() == qualifier0);
227    assertTrue(cell0.getValueArray()     == value0);
228
229    // Verify timestamp
230    assertTrue(cell0.getTimestamp()      == put.getTimestamp());
231
232    // Verify the cell of family:qualifier1
233    Cell cell1 = put.get(family, qualifier1).get(0);
234
235    // Verify no local copy is made for family, qualifier or value
236    assertTrue(cell1.getFamilyArray()    == family);
237    assertTrue(cell1.getQualifierArray() == qualifier1);
238    assertTrue(cell1.getValueArray()     == value1);
239
240    // Verify timestamp
241    assertTrue(cell1.getTimestamp()      == ts1);
242  }
243}