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.hamcrest.CoreMatchers.instanceOf;
021import static org.hamcrest.MatcherAssert.assertThat;
022import static org.junit.Assert.assertEquals;
023import static org.junit.Assert.assertFalse;
024import static org.junit.Assert.assertNotNull;
025import static org.junit.Assert.assertTrue;
026import static org.junit.Assert.fail;
027
028import java.io.IOException;
029import java.util.ArrayList;
030import java.util.Arrays;
031import java.util.Collection;
032import java.util.EnumSet;
033import java.util.HashSet;
034import java.util.List;
035import java.util.NavigableMap;
036import org.apache.hadoop.conf.Configuration;
037import org.apache.hadoop.hbase.Cell;
038import org.apache.hadoop.hbase.CellUtil;
039import org.apache.hadoop.hbase.ClusterMetrics.Option;
040import org.apache.hadoop.hbase.HBaseClassTestRule;
041import org.apache.hadoop.hbase.HConstants;
042import org.apache.hadoop.hbase.KeyValue;
043import org.apache.hadoop.hbase.SingleProcessHBaseCluster;
044import org.apache.hadoop.hbase.TableName;
045import org.apache.hadoop.hbase.TableNameTestRule;
046import org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint;
047import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException;
048import org.apache.hadoop.hbase.testclassification.ClientTests;
049import org.apache.hadoop.hbase.testclassification.LargeTests;
050import org.apache.hadoop.hbase.util.Bytes;
051import org.junit.AfterClass;
052import org.junit.Assume;
053import org.junit.ClassRule;
054import org.junit.Rule;
055import org.junit.Test;
056import org.junit.experimental.categories.Category;
057import org.junit.runner.RunWith;
058import org.junit.runners.Parameterized;
059import org.slf4j.Logger;
060import org.slf4j.LoggerFactory;
061
062import org.apache.hbase.thirdparty.com.google.common.collect.Iterables;
063
064/**
065 * Run tests that use the HBase clients; {@link Table}. Sets up the HBase mini cluster once at start
066 * and runs through all client tests. Each creates a table named for the method and does its stuff
067 * against that. Parameterized to run with different registry implementations.
068 */
069@Category({ LargeTests.class, ClientTests.class })
070@SuppressWarnings("deprecation")
071@RunWith(Parameterized.class)
072public class TestFromClientSide4 extends FromClientSideBase {
073  private static final Logger LOG = LoggerFactory.getLogger(TestFromClientSide4.class);
074  @ClassRule
075  public static final HBaseClassTestRule CLASS_RULE =
076    HBaseClassTestRule.forClass(TestFromClientSide4.class);
077  @Rule
078  public TableNameTestRule name = new TableNameTestRule();
079
080  // To keep the child classes happy.
081  TestFromClientSide4() {
082  }
083
084  public TestFromClientSide4(Class registry, int numHedgedReqs) throws Exception {
085    initialize(registry, numHedgedReqs, MultiRowMutationEndpoint.class);
086  }
087
088  @Parameterized.Parameters
089  public static Collection parameters() {
090    return Arrays.asList(new Object[][] { { MasterRegistry.class, 1 }, { MasterRegistry.class, 2 },
091      { ZKConnectionRegistry.class, 1 } });
092  }
093
094  @AfterClass
095  public static void tearDownAfterClass() throws Exception {
096    afterClass();
097  }
098
099  /**
100   * Test batch operations with combination of valid and invalid args
101   */
102  @Test
103  public void testBatchOperationsWithErrors() throws Exception {
104    final TableName tableName = name.getTableName();
105    try (Table foo = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY }, 10)) {
106
107      int NUM_OPS = 100;
108
109      // 1.1 Put with no column families (local validation, runtime exception)
110      List<Put> puts = new ArrayList<>(NUM_OPS);
111      for (int i = 0; i != NUM_OPS; i++) {
112        Put put = new Put(Bytes.toBytes(i));
113        puts.add(put);
114      }
115
116      try {
117        foo.put(puts);
118        fail();
119      } catch (IllegalArgumentException e) {
120        // expected
121        assertEquals(NUM_OPS, puts.size());
122      }
123
124      // 1.2 Put with invalid column family
125      puts.clear();
126      for (int i = 0; i < NUM_OPS; i++) {
127        Put put = new Put(Bytes.toBytes(i));
128        put.addColumn((i % 2) == 0 ? FAMILY : INVALID_FAMILY, FAMILY, Bytes.toBytes(i));
129        puts.add(put);
130      }
131
132      try {
133        foo.put(puts);
134        fail();
135      } catch (RetriesExhaustedException e) {
136        // expected
137        assertThat(e.getCause(), instanceOf(NoSuchColumnFamilyException.class));
138      }
139
140      // 2.1 Get non-existent rows
141      List<Get> gets = new ArrayList<>(NUM_OPS);
142      for (int i = 0; i < NUM_OPS; i++) {
143        Get get = new Get(Bytes.toBytes(i));
144        gets.add(get);
145      }
146      Result[] getsResult = foo.get(gets);
147      assertNotNull(getsResult);
148      assertEquals(NUM_OPS, getsResult.length);
149      for (int i = 0; i < NUM_OPS; i++) {
150        Result getResult = getsResult[i];
151        if (i % 2 == 0) {
152          assertFalse(getResult.isEmpty());
153        } else {
154          assertTrue(getResult.isEmpty());
155        }
156      }
157
158      // 2.2 Get with invalid column family
159      gets.clear();
160      for (int i = 0; i < NUM_OPS; i++) {
161        Get get = new Get(Bytes.toBytes(i));
162        get.addColumn((i % 2) == 0 ? FAMILY : INVALID_FAMILY, FAMILY);
163        gets.add(get);
164      }
165      try {
166        foo.get(gets);
167        fail();
168      } catch (RetriesExhaustedException e) {
169        // expected
170        assertThat(e.getCause(), instanceOf(NoSuchColumnFamilyException.class));
171      }
172
173      // 3.1 Delete with invalid column family
174      List<Delete> deletes = new ArrayList<>(NUM_OPS);
175      for (int i = 0; i < NUM_OPS; i++) {
176        Delete delete = new Delete(Bytes.toBytes(i));
177        delete.addColumn((i % 2) == 0 ? FAMILY : INVALID_FAMILY, FAMILY);
178        deletes.add(delete);
179      }
180      try {
181        foo.delete(deletes);
182        fail();
183      } catch (RetriesExhaustedException e) {
184        // expected
185        assertThat(e.getCause(), instanceOf(NoSuchColumnFamilyException.class));
186      }
187
188      // all valid rows should have been deleted
189      gets.clear();
190      for (int i = 0; i < NUM_OPS; i++) {
191        Get get = new Get(Bytes.toBytes(i));
192        gets.add(get);
193      }
194      getsResult = foo.get(gets);
195      assertNotNull(getsResult);
196      assertEquals(NUM_OPS, getsResult.length);
197      for (Result getResult : getsResult) {
198        assertTrue(getResult.isEmpty());
199      }
200
201      // 3.2 Delete non-existent rows
202      deletes.clear();
203      for (int i = 0; i < NUM_OPS; i++) {
204        Delete delete = new Delete(Bytes.toBytes(i));
205        deletes.add(delete);
206      }
207      foo.delete(deletes);
208    }
209  }
210
211  //
212  // JIRA Testers
213  //
214
215  /**
216   * HBASE-867 If millions of columns in a column family, hbase scanner won't come up Test will
217   * create numRows rows, each with numColsPerRow columns (1 version each), and attempt to scan them
218   * all. To test at scale, up numColsPerRow to the millions (have not gotten that to work running
219   * as junit though)
220   */
221  @Test
222  public void testJiraTest867() throws Exception {
223    int numRows = 10;
224    int numColsPerRow = 2000;
225
226    final TableName tableName = name.getTableName();
227
228    byte[][] ROWS = makeN(ROW, numRows);
229    byte[][] QUALIFIERS = makeN(QUALIFIER, numColsPerRow);
230
231    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
232
233      // Insert rows
234
235      for (int i = 0; i < numRows; i++) {
236        Put put = new Put(ROWS[i]);
237        put.setDurability(Durability.SKIP_WAL);
238        for (int j = 0; j < numColsPerRow; j++) {
239          put.addColumn(FAMILY, QUALIFIERS[j], QUALIFIERS[j]);
240        }
241        assertEquals("Put expected to contain " + numColsPerRow + " columns but " + "only contains "
242          + put.size(), put.size(), numColsPerRow);
243        ht.put(put);
244      }
245
246      // Get a row
247      Get get = new Get(ROWS[numRows - 1]);
248      Result result = ht.get(get);
249      assertNumKeys(result, numColsPerRow);
250      Cell[] keys = result.rawCells();
251      for (int i = 0; i < result.size(); i++) {
252        assertKey(keys[i], ROWS[numRows - 1], FAMILY, QUALIFIERS[i], QUALIFIERS[i]);
253      }
254
255      // Scan the rows
256      Scan scan = new Scan();
257      try (ResultScanner scanner = ht.getScanner(scan)) {
258        int rowCount = 0;
259        while ((result = scanner.next()) != null) {
260          assertNumKeys(result, numColsPerRow);
261          Cell[] kvs = result.rawCells();
262          for (int i = 0; i < numColsPerRow; i++) {
263            assertKey(kvs[i], ROWS[rowCount], FAMILY, QUALIFIERS[i], QUALIFIERS[i]);
264          }
265          rowCount++;
266        }
267        assertEquals(
268          "Expected to scan " + numRows + " rows but actually scanned " + rowCount + " rows",
269          rowCount, numRows);
270      }
271
272      // flush and try again
273
274      TEST_UTIL.flush();
275
276      // Get a row
277      get = new Get(ROWS[numRows - 1]);
278      result = ht.get(get);
279      assertNumKeys(result, numColsPerRow);
280      keys = result.rawCells();
281      for (int i = 0; i < result.size(); i++) {
282        assertKey(keys[i], ROWS[numRows - 1], FAMILY, QUALIFIERS[i], QUALIFIERS[i]);
283      }
284
285      // Scan the rows
286      scan = new Scan();
287      try (ResultScanner scanner = ht.getScanner(scan)) {
288        int rowCount = 0;
289        while ((result = scanner.next()) != null) {
290          assertNumKeys(result, numColsPerRow);
291          Cell[] kvs = result.rawCells();
292          for (int i = 0; i < numColsPerRow; i++) {
293            assertKey(kvs[i], ROWS[rowCount], FAMILY, QUALIFIERS[i], QUALIFIERS[i]);
294          }
295          rowCount++;
296        }
297        assertEquals(
298          "Expected to scan " + numRows + " rows but actually scanned " + rowCount + " rows",
299          rowCount, numRows);
300      }
301    }
302  }
303
304  /**
305   * HBASE-861 get with timestamp will return a value if there is a version with an earlier
306   * timestamp
307   */
308  @Test
309  public void testJiraTest861() throws Exception {
310    final TableName tableName = name.getTableName();
311    byte[][] VALUES = makeNAscii(VALUE, 7);
312    long[] STAMPS = makeStamps(7);
313
314    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 10)) {
315
316      // Insert three versions
317
318      Put put = new Put(ROW);
319      put.addColumn(FAMILY, QUALIFIER, STAMPS[3], VALUES[3]);
320      put.addColumn(FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
321      put.addColumn(FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
322      ht.put(put);
323
324      // Get the middle value
325      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
326
327      // Try to get one version before (expect fail)
328      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[1]);
329
330      // Try to get one version after (expect fail)
331      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[5]);
332
333      // Try same from storefile
334      TEST_UTIL.flush();
335      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
336      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[1]);
337      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[5]);
338
339      // Insert two more versions surrounding others, into memstore
340      put = new Put(ROW);
341      put.addColumn(FAMILY, QUALIFIER, STAMPS[0], VALUES[0]);
342      put.addColumn(FAMILY, QUALIFIER, STAMPS[6], VALUES[6]);
343      ht.put(put);
344
345      // Check we can get everything we should and can't get what we shouldn't
346      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[0], VALUES[0]);
347      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[1]);
348      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
349      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[3], VALUES[3]);
350      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
351      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[5]);
352      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[6], VALUES[6]);
353
354      // Try same from two storefiles
355      TEST_UTIL.flush();
356      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[0], VALUES[0]);
357      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[1]);
358      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
359      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[3], VALUES[3]);
360      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
361      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[5]);
362      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[6], VALUES[6]);
363    }
364  }
365
366  /**
367   * HBASE-33 Add a HTable get/obtainScanner method that retrieves all versions of a particular
368   * column and row between two timestamps
369   */
370  @Test
371  public void testJiraTest33() throws Exception {
372    final TableName tableName = name.getTableName();
373    byte[][] VALUES = makeNAscii(VALUE, 7);
374    long[] STAMPS = makeStamps(7);
375
376    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 10)) {
377
378      // Insert lots versions
379
380      Put put = new Put(ROW);
381      put.addColumn(FAMILY, QUALIFIER, STAMPS[0], VALUES[0]);
382      put.addColumn(FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
383      put.addColumn(FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
384      put.addColumn(FAMILY, QUALIFIER, STAMPS[3], VALUES[3]);
385      put.addColumn(FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
386      put.addColumn(FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
387      ht.put(put);
388
389      getVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
390      getVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 2);
391      getVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 4, 5);
392      getVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 2, 3);
393
394      scanVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
395      scanVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 2);
396      scanVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 4, 5);
397      scanVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 2, 3);
398
399      // Try same from storefile
400      TEST_UTIL.flush();
401
402      getVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
403      getVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 2);
404      getVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 4, 5);
405      getVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 2, 3);
406
407      scanVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
408      scanVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 2);
409      scanVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 4, 5);
410      scanVersionRangeAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 2, 3);
411    }
412  }
413
414  /**
415   * HBASE-1014 commit(BatchUpdate) method should return timestamp
416   */
417  @Test
418  public void testJiraTest1014() throws Exception {
419    final TableName tableName = name.getTableName();
420
421    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 10)) {
422
423      long manualStamp = 12345;
424
425      // Insert lots versions
426
427      Put put = new Put(ROW);
428      put.addColumn(FAMILY, QUALIFIER, manualStamp, VALUE);
429      ht.put(put);
430
431      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, manualStamp, VALUE);
432      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, manualStamp - 1);
433      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, manualStamp + 1);
434    }
435  }
436
437  /**
438   * HBASE-1182 Scan for columns > some timestamp
439   */
440  @Test
441  public void testJiraTest1182() throws Exception {
442    final TableName tableName = name.getTableName();
443    byte[][] VALUES = makeNAscii(VALUE, 7);
444    long[] STAMPS = makeStamps(7);
445
446    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 10)) {
447
448      // Insert lots versions
449
450      Put put = new Put(ROW);
451      put.addColumn(FAMILY, QUALIFIER, STAMPS[0], VALUES[0]);
452      put.addColumn(FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
453      put.addColumn(FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
454      put.addColumn(FAMILY, QUALIFIER, STAMPS[3], VALUES[3]);
455      put.addColumn(FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
456      put.addColumn(FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
457      ht.put(put);
458
459      getVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
460      getVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 2, 5);
461      getVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 4, 5);
462
463      scanVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
464      scanVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 2, 5);
465      scanVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 4, 5);
466
467      // Try same from storefile
468      TEST_UTIL.flush();
469
470      getVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
471      getVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 2, 5);
472      getVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 4, 5);
473
474      scanVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
475      scanVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 2, 5);
476      scanVersionRangeAndVerifyGreaterThan(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 4, 5);
477    }
478  }
479
480  /**
481   * HBASE-52 Add a means of scanning over all versions
482   */
483  @Test
484  public void testJiraTest52() throws Exception {
485    final TableName tableName = name.getTableName();
486    byte[][] VALUES = makeNAscii(VALUE, 7);
487    long[] STAMPS = makeStamps(7);
488
489    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 10)) {
490
491      // Insert lots versions
492
493      Put put = new Put(ROW);
494      put.addColumn(FAMILY, QUALIFIER, STAMPS[0], VALUES[0]);
495      put.addColumn(FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
496      put.addColumn(FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
497      put.addColumn(FAMILY, QUALIFIER, STAMPS[3], VALUES[3]);
498      put.addColumn(FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
499      put.addColumn(FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
500      ht.put(put);
501
502      getAllVersionsAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
503
504      scanAllVersionsAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
505
506      // Try same from storefile
507      TEST_UTIL.flush();
508
509      getAllVersionsAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
510
511      scanAllVersionsAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS, VALUES, 0, 5);
512    }
513  }
514
515  @Test
516  @SuppressWarnings("checkstyle:MethodLength")
517  public void testDuplicateVersions() throws Exception {
518    final TableName tableName = name.getTableName();
519
520    long[] STAMPS = makeStamps(20);
521    byte[][] VALUES = makeNAscii(VALUE, 20);
522
523    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 10)) {
524
525      // Insert 4 versions of same column
526      Put put = new Put(ROW);
527      put.addColumn(FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
528      put.addColumn(FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
529      put.addColumn(FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
530      put.addColumn(FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
531      ht.put(put);
532
533      // Verify we can get each one properly
534      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
535      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
536      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
537      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
538      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
539      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
540      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
541      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
542
543      // Verify we don't accidentally get others
544      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
545      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[3]);
546      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[6]);
547      scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
548      scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[3]);
549      scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[6]);
550
551      // Ensure maxVersions in query is respected
552      Get get = new Get(ROW);
553      get.addColumn(FAMILY, QUALIFIER);
554      get.readVersions(2);
555      Result result = ht.get(get);
556      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[] { STAMPS[4], STAMPS[5] },
557        new byte[][] { VALUES[4], VALUES[5] }, 0, 1);
558
559      Scan scan = new Scan().withStartRow(ROW);
560      scan.addColumn(FAMILY, QUALIFIER);
561      scan.readVersions(2);
562      result = getSingleScanResult(ht, scan);
563      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[] { STAMPS[4], STAMPS[5] },
564        new byte[][] { VALUES[4], VALUES[5] }, 0, 1);
565
566      // Flush and redo
567
568      TEST_UTIL.flush();
569
570      // Verify we can get each one properly
571      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
572      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
573      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
574      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
575      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
576      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
577      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
578      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
579
580      // Verify we don't accidentally get others
581      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
582      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[3]);
583      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[6]);
584      scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
585      scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[3]);
586      scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[6]);
587
588      // Ensure maxVersions in query is respected
589      get = new Get(ROW);
590      get.addColumn(FAMILY, QUALIFIER);
591      get.readVersions(2);
592      result = ht.get(get);
593      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[] { STAMPS[4], STAMPS[5] },
594        new byte[][] { VALUES[4], VALUES[5] }, 0, 1);
595
596      scan = new Scan().withStartRow(ROW);
597      scan.addColumn(FAMILY, QUALIFIER);
598      scan.readVersions(2);
599      result = getSingleScanResult(ht, scan);
600      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[] { STAMPS[4], STAMPS[5] },
601        new byte[][] { VALUES[4], VALUES[5] }, 0, 1);
602
603      // Add some memstore and retest
604
605      // Insert 4 more versions of same column and a dupe
606      put = new Put(ROW);
607      put.addColumn(FAMILY, QUALIFIER, STAMPS[3], VALUES[3]);
608      put.addColumn(FAMILY, QUALIFIER, STAMPS[4], VALUES[14]);
609      put.addColumn(FAMILY, QUALIFIER, STAMPS[6], VALUES[6]);
610      put.addColumn(FAMILY, QUALIFIER, STAMPS[7], VALUES[7]);
611      put.addColumn(FAMILY, QUALIFIER, STAMPS[8], VALUES[8]);
612      ht.put(put);
613
614      // Ensure maxVersions in query is respected
615      get = new Get(ROW);
616      get.addColumn(FAMILY, QUALIFIER);
617      get.readVersions(7);
618      result = ht.get(get);
619      assertNResult(result, ROW, FAMILY, QUALIFIER,
620        new long[] { STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7], STAMPS[8] },
621        new byte[][] { VALUES[2], VALUES[3], VALUES[14], VALUES[5], VALUES[6], VALUES[7],
622          VALUES[8] },
623        0, 6);
624
625      scan = new Scan().withStartRow(ROW);
626      scan.addColumn(FAMILY, QUALIFIER);
627      scan.readVersions(7);
628      result = getSingleScanResult(ht, scan);
629      assertNResult(result, ROW, FAMILY, QUALIFIER,
630        new long[] { STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7], STAMPS[8] },
631        new byte[][] { VALUES[2], VALUES[3], VALUES[14], VALUES[5], VALUES[6], VALUES[7],
632          VALUES[8] },
633        0, 6);
634
635      get = new Get(ROW);
636      get.readVersions(7);
637      result = ht.get(get);
638      assertNResult(result, ROW, FAMILY, QUALIFIER,
639        new long[] { STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7], STAMPS[8] },
640        new byte[][] { VALUES[2], VALUES[3], VALUES[14], VALUES[5], VALUES[6], VALUES[7],
641          VALUES[8] },
642        0, 6);
643
644      scan = new Scan().withStartRow(ROW);
645      scan.readVersions(7);
646      result = getSingleScanResult(ht, scan);
647      assertNResult(result, ROW, FAMILY, QUALIFIER,
648        new long[] { STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7], STAMPS[8] },
649        new byte[][] { VALUES[2], VALUES[3], VALUES[14], VALUES[5], VALUES[6], VALUES[7],
650          VALUES[8] },
651        0, 6);
652
653      // Verify we can get each one properly
654      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
655      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
656      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[14]);
657      getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[7], VALUES[7]);
658      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
659      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
660      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[14]);
661      scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[7], VALUES[7]);
662
663      // Verify we don't accidentally get others
664      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
665      getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[9]);
666      scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
667      scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[9]);
668
669      // Ensure maxVersions of table is respected
670
671      TEST_UTIL.flush();
672
673      // Insert 4 more versions of same column and a dupe
674      put = new Put(ROW);
675      put.addColumn(FAMILY, QUALIFIER, STAMPS[9], VALUES[9]);
676      put.addColumn(FAMILY, QUALIFIER, STAMPS[11], VALUES[11]);
677      put.addColumn(FAMILY, QUALIFIER, STAMPS[13], VALUES[13]);
678      put.addColumn(FAMILY, QUALIFIER, STAMPS[15], VALUES[15]);
679      ht.put(put);
680
681      get = new Get(ROW);
682      get.addColumn(FAMILY, QUALIFIER);
683      get.readVersions(Integer.MAX_VALUE);
684      result = ht.get(get);
685      assertNResult(result, ROW, FAMILY, QUALIFIER,
686        new long[] { STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7], STAMPS[8], STAMPS[9],
687          STAMPS[11], STAMPS[13], STAMPS[15] },
688        new byte[][] { VALUES[3], VALUES[14], VALUES[5], VALUES[6], VALUES[7], VALUES[8], VALUES[9],
689          VALUES[11], VALUES[13], VALUES[15] },
690        0, 9);
691
692      scan = new Scan().withStartRow(ROW);
693      scan.addColumn(FAMILY, QUALIFIER);
694      scan.readVersions(Integer.MAX_VALUE);
695      result = getSingleScanResult(ht, scan);
696      assertNResult(result, ROW, FAMILY, QUALIFIER,
697        new long[] { STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7], STAMPS[8], STAMPS[9],
698          STAMPS[11], STAMPS[13], STAMPS[15] },
699        new byte[][] { VALUES[3], VALUES[14], VALUES[5], VALUES[6], VALUES[7], VALUES[8], VALUES[9],
700          VALUES[11], VALUES[13], VALUES[15] },
701        0, 9);
702
703      // Delete a version in the memstore and a version in a storefile
704      Delete delete = new Delete(ROW);
705      delete.addColumn(FAMILY, QUALIFIER, STAMPS[11]);
706      delete.addColumn(FAMILY, QUALIFIER, STAMPS[7]);
707      ht.delete(delete);
708
709      // Test that it's gone
710      get = new Get(ROW);
711      get.addColumn(FAMILY, QUALIFIER);
712      get.readVersions(Integer.MAX_VALUE);
713      result = ht.get(get);
714      assertNResult(result, ROW, FAMILY, QUALIFIER,
715        new long[] { STAMPS[1], STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[8],
716          STAMPS[9], STAMPS[13], STAMPS[15] },
717        new byte[][] { VALUES[1], VALUES[2], VALUES[3], VALUES[14], VALUES[5], VALUES[6], VALUES[8],
718          VALUES[9], VALUES[13], VALUES[15] },
719        0, 9);
720
721      scan = new Scan().withStartRow(ROW);
722      scan.addColumn(FAMILY, QUALIFIER);
723      scan.readVersions(Integer.MAX_VALUE);
724      result = getSingleScanResult(ht, scan);
725      assertNResult(result, ROW, FAMILY, QUALIFIER,
726        new long[] { STAMPS[1], STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[8],
727          STAMPS[9], STAMPS[13], STAMPS[15] },
728        new byte[][] { VALUES[1], VALUES[2], VALUES[3], VALUES[14], VALUES[5], VALUES[6], VALUES[8],
729          VALUES[9], VALUES[13], VALUES[15] },
730        0, 9);
731    }
732  }
733
734  @Test
735  public void testUpdates() throws Exception {
736    final TableName tableName = name.getTableName();
737    try (Table hTable = TEST_UTIL.createTable(tableName, FAMILY, 10)) {
738
739      // Write a column with values at timestamp 1, 2 and 3
740      byte[] row = Bytes.toBytes("row1");
741      byte[] qualifier = Bytes.toBytes("myCol");
742      Put put = new Put(row);
743      put.addColumn(FAMILY, qualifier, 1L, Bytes.toBytes("AAA"));
744      hTable.put(put);
745
746      put = new Put(row);
747      put.addColumn(FAMILY, qualifier, 2L, Bytes.toBytes("BBB"));
748      hTable.put(put);
749
750      put = new Put(row);
751      put.addColumn(FAMILY, qualifier, 3L, Bytes.toBytes("EEE"));
752      hTable.put(put);
753
754      Get get = new Get(row);
755      get.addColumn(FAMILY, qualifier);
756      get.readAllVersions();
757
758      // Check that the column indeed has the right values at timestamps 1 and
759      // 2
760      Result result = hTable.get(get);
761      NavigableMap<Long, byte[]> navigableMap = result.getMap().get(FAMILY).get(qualifier);
762      assertEquals("AAA", Bytes.toString(navigableMap.get(1L)));
763      assertEquals("BBB", Bytes.toString(navigableMap.get(2L)));
764
765      // Update the value at timestamp 1
766      put = new Put(row);
767      put.addColumn(FAMILY, qualifier, 1L, Bytes.toBytes("CCC"));
768      hTable.put(put);
769
770      // Update the value at timestamp 2
771      put = new Put(row);
772      put.addColumn(FAMILY, qualifier, 2L, Bytes.toBytes("DDD"));
773      hTable.put(put);
774
775      // Check that the values at timestamp 2 and 1 got updated
776      result = hTable.get(get);
777      navigableMap = result.getMap().get(FAMILY).get(qualifier);
778      assertEquals("CCC", Bytes.toString(navigableMap.get(1L)));
779      assertEquals("DDD", Bytes.toString(navigableMap.get(2L)));
780    }
781  }
782
783  @Test
784  public void testUpdatesWithMajorCompaction() throws Exception {
785    final TableName tableName = name.getTableName();
786    try (Table hTable = TEST_UTIL.createTable(tableName, FAMILY, 10);
787      Admin admin = TEST_UTIL.getAdmin()) {
788
789      // Write a column with values at timestamp 1, 2 and 3
790      byte[] row = Bytes.toBytes("row2");
791      byte[] qualifier = Bytes.toBytes("myCol");
792      Put put = new Put(row);
793      put.addColumn(FAMILY, qualifier, 1L, Bytes.toBytes("AAA"));
794      hTable.put(put);
795
796      put = new Put(row);
797      put.addColumn(FAMILY, qualifier, 2L, Bytes.toBytes("BBB"));
798      hTable.put(put);
799
800      put = new Put(row);
801      put.addColumn(FAMILY, qualifier, 3L, Bytes.toBytes("EEE"));
802      hTable.put(put);
803
804      Get get = new Get(row);
805      get.addColumn(FAMILY, qualifier);
806      get.readAllVersions();
807
808      // Check that the column indeed has the right values at timestamps 1 and
809      // 2
810      Result result = hTable.get(get);
811      NavigableMap<Long, byte[]> navigableMap = result.getMap().get(FAMILY).get(qualifier);
812      assertEquals("AAA", Bytes.toString(navigableMap.get(1L)));
813      assertEquals("BBB", Bytes.toString(navigableMap.get(2L)));
814
815      // Trigger a major compaction
816      admin.flush(tableName);
817      admin.majorCompact(tableName);
818      Thread.sleep(6000);
819
820      // Update the value at timestamp 1
821      put = new Put(row);
822      put.addColumn(FAMILY, qualifier, 1L, Bytes.toBytes("CCC"));
823      hTable.put(put);
824
825      // Update the value at timestamp 2
826      put = new Put(row);
827      put.addColumn(FAMILY, qualifier, 2L, Bytes.toBytes("DDD"));
828      hTable.put(put);
829
830      // Trigger a major compaction
831      admin.flush(tableName);
832      admin.majorCompact(tableName);
833      Thread.sleep(6000);
834
835      // Check that the values at timestamp 2 and 1 got updated
836      result = hTable.get(get);
837      navigableMap = result.getMap().get(FAMILY).get(qualifier);
838      assertEquals("CCC", Bytes.toString(navigableMap.get(1L)));
839      assertEquals("DDD", Bytes.toString(navigableMap.get(2L)));
840    }
841  }
842
843  @Test
844  public void testMajorCompactionBetweenTwoUpdates() throws Exception {
845    final TableName tableName = name.getTableName();
846    try (Table hTable = TEST_UTIL.createTable(tableName, FAMILY, 10);
847      Admin admin = TEST_UTIL.getAdmin()) {
848
849      // Write a column with values at timestamp 1, 2 and 3
850      byte[] row = Bytes.toBytes("row3");
851      byte[] qualifier = Bytes.toBytes("myCol");
852      Put put = new Put(row);
853      put.addColumn(FAMILY, qualifier, 1L, Bytes.toBytes("AAA"));
854      hTable.put(put);
855
856      put = new Put(row);
857      put.addColumn(FAMILY, qualifier, 2L, Bytes.toBytes("BBB"));
858      hTable.put(put);
859
860      put = new Put(row);
861      put.addColumn(FAMILY, qualifier, 3L, Bytes.toBytes("EEE"));
862      hTable.put(put);
863
864      Get get = new Get(row);
865      get.addColumn(FAMILY, qualifier);
866      get.readAllVersions();
867
868      // Check that the column indeed has the right values at timestamps 1 and
869      // 2
870      Result result = hTable.get(get);
871      NavigableMap<Long, byte[]> navigableMap = result.getMap().get(FAMILY).get(qualifier);
872      assertEquals("AAA", Bytes.toString(navigableMap.get(1L)));
873      assertEquals("BBB", Bytes.toString(navigableMap.get(2L)));
874
875      // Trigger a major compaction
876      admin.flush(tableName);
877      admin.majorCompact(tableName);
878      Thread.sleep(6000);
879
880      // Update the value at timestamp 1
881      put = new Put(row);
882      put.addColumn(FAMILY, qualifier, 1L, Bytes.toBytes("CCC"));
883      hTable.put(put);
884
885      // Trigger a major compaction
886      admin.flush(tableName);
887      admin.majorCompact(tableName);
888      Thread.sleep(6000);
889
890      // Update the value at timestamp 2
891      put = new Put(row);
892      put.addColumn(FAMILY, qualifier, 2L, Bytes.toBytes("DDD"));
893      hTable.put(put);
894
895      // Trigger a major compaction
896      admin.flush(tableName);
897      admin.majorCompact(tableName);
898      Thread.sleep(6000);
899
900      // Check that the values at timestamp 2 and 1 got updated
901      result = hTable.get(get);
902      navigableMap = result.getMap().get(FAMILY).get(qualifier);
903
904      assertEquals("CCC", Bytes.toString(navigableMap.get(1L)));
905      assertEquals("DDD", Bytes.toString(navigableMap.get(2L)));
906    }
907  }
908
909  @Test
910  public void testGet_EmptyTable() throws IOException {
911    try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) {
912      Get get = new Get(ROW);
913      get.addFamily(FAMILY);
914      Result r = table.get(get);
915      assertTrue(r.isEmpty());
916    }
917  }
918
919  @Test
920  public void testGet_NullQualifier() throws IOException {
921    try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) {
922      Put put = new Put(ROW);
923      put.addColumn(FAMILY, QUALIFIER, VALUE);
924      table.put(put);
925
926      put = new Put(ROW);
927      put.addColumn(FAMILY, null, VALUE);
928      table.put(put);
929      LOG.info("Row put");
930
931      Get get = new Get(ROW);
932      get.addColumn(FAMILY, null);
933      Result r = table.get(get);
934      assertEquals(1, r.size());
935
936      get = new Get(ROW);
937      get.addFamily(FAMILY);
938      r = table.get(get);
939      assertEquals(2, r.size());
940    }
941  }
942
943  @Test
944  public void testGet_NonExistentRow() throws IOException {
945    try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) {
946      Put put = new Put(ROW);
947      put.addColumn(FAMILY, QUALIFIER, VALUE);
948      table.put(put);
949      LOG.info("Row put");
950
951      Get get = new Get(ROW);
952      get.addFamily(FAMILY);
953      Result r = table.get(get);
954      assertFalse(r.isEmpty());
955      System.out.println("Row retrieved successfully");
956
957      byte[] missingrow = Bytes.toBytes("missingrow");
958      get = new Get(missingrow);
959      get.addFamily(FAMILY);
960      r = table.get(get);
961      assertTrue(r.isEmpty());
962      LOG.info("Row missing as it should be");
963    }
964  }
965
966  @Test
967  public void testPut() throws IOException {
968    final byte[] CONTENTS_FAMILY = Bytes.toBytes("contents");
969    final byte[] SMALL_FAMILY = Bytes.toBytes("smallfam");
970    final byte[] row1 = Bytes.toBytes("row1");
971    final byte[] row2 = Bytes.toBytes("row2");
972    final byte[] value = Bytes.toBytes("abcd");
973    try (Table table =
974      TEST_UTIL.createTable(name.getTableName(), new byte[][] { CONTENTS_FAMILY, SMALL_FAMILY })) {
975      Put put = new Put(row1);
976      put.addColumn(CONTENTS_FAMILY, null, value);
977      table.put(put);
978
979      put = new Put(row2);
980      put.addColumn(CONTENTS_FAMILY, null, value);
981
982      assertEquals(1, put.size());
983      assertEquals(1, put.getFamilyCellMap().get(CONTENTS_FAMILY).size());
984
985      // KeyValue v1 expectation. Cast for now until we go all Cell all the time. TODO
986      KeyValue kv = (KeyValue) put.getFamilyCellMap().get(CONTENTS_FAMILY).get(0);
987
988      assertTrue(Bytes.equals(CellUtil.cloneFamily(kv), CONTENTS_FAMILY));
989      // will it return null or an empty byte array?
990      assertTrue(Bytes.equals(CellUtil.cloneQualifier(kv), new byte[0]));
991
992      assertTrue(Bytes.equals(CellUtil.cloneValue(kv), value));
993
994      table.put(put);
995
996      Scan scan = new Scan();
997      scan.addColumn(CONTENTS_FAMILY, null);
998      try (ResultScanner scanner = table.getScanner(scan)) {
999        for (Result r : scanner) {
1000          for (Cell key : r.rawCells()) {
1001            System.out.println(Bytes.toString(r.getRow()) + ": " + key.toString());
1002          }
1003        }
1004      }
1005    }
1006  }
1007
1008  @Test
1009  public void testPutNoCF() throws IOException {
1010    final byte[] BAD_FAM = Bytes.toBytes("BAD_CF");
1011    final byte[] VAL = Bytes.toBytes(100);
1012    try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) {
1013      boolean caughtNSCFE = false;
1014
1015      try {
1016        Put p = new Put(ROW);
1017        p.addColumn(BAD_FAM, QUALIFIER, VAL);
1018        table.put(p);
1019      } catch (Exception e) {
1020        caughtNSCFE = e instanceof NoSuchColumnFamilyException;
1021      }
1022      assertTrue("Should throw NoSuchColumnFamilyException", caughtNSCFE);
1023    }
1024  }
1025
1026  @Test
1027  public void testRowsPut() throws IOException {
1028    final byte[] CONTENTS_FAMILY = Bytes.toBytes("contents");
1029    final byte[] SMALL_FAMILY = Bytes.toBytes("smallfam");
1030    final int NB_BATCH_ROWS = 10;
1031    final byte[] value = Bytes.toBytes("abcd");
1032    try (Table table =
1033      TEST_UTIL.createTable(name.getTableName(), new byte[][] { CONTENTS_FAMILY, SMALL_FAMILY })) {
1034      ArrayList<Put> rowsUpdate = new ArrayList<>();
1035      for (int i = 0; i < NB_BATCH_ROWS; i++) {
1036        byte[] row = Bytes.toBytes("row" + i);
1037        Put put = new Put(row);
1038        put.setDurability(Durability.SKIP_WAL);
1039        put.addColumn(CONTENTS_FAMILY, null, value);
1040        rowsUpdate.add(put);
1041      }
1042      table.put(rowsUpdate);
1043      Scan scan = new Scan();
1044      scan.addFamily(CONTENTS_FAMILY);
1045      try (ResultScanner scanner = table.getScanner(scan)) {
1046        int nbRows = Iterables.size(scanner);
1047        assertEquals(NB_BATCH_ROWS, nbRows);
1048      }
1049    }
1050  }
1051
1052  @Test
1053  public void testRowsPutBufferedManyManyFlushes() throws IOException {
1054    final byte[] CONTENTS_FAMILY = Bytes.toBytes("contents");
1055    final byte[] SMALL_FAMILY = Bytes.toBytes("smallfam");
1056    final byte[] value = Bytes.toBytes("abcd");
1057    final int NB_BATCH_ROWS = 10;
1058    try (Table table =
1059      TEST_UTIL.createTable(name.getTableName(), new byte[][] { CONTENTS_FAMILY, SMALL_FAMILY })) {
1060      ArrayList<Put> rowsUpdate = new ArrayList<>();
1061      for (int i = 0; i < NB_BATCH_ROWS * 10; i++) {
1062        byte[] row = Bytes.toBytes("row" + i);
1063        Put put = new Put(row);
1064        put.setDurability(Durability.SKIP_WAL);
1065        put.addColumn(CONTENTS_FAMILY, null, value);
1066        rowsUpdate.add(put);
1067      }
1068      table.put(rowsUpdate);
1069
1070      Scan scan = new Scan();
1071      scan.addFamily(CONTENTS_FAMILY);
1072      try (ResultScanner scanner = table.getScanner(scan)) {
1073        int nbRows = Iterables.size(scanner);
1074        assertEquals(NB_BATCH_ROWS * 10, nbRows);
1075      }
1076    }
1077  }
1078
1079  @Test
1080  public void testAddKeyValue() {
1081    final byte[] CONTENTS_FAMILY = Bytes.toBytes("contents");
1082    final byte[] value = Bytes.toBytes("abcd");
1083    final byte[] row1 = Bytes.toBytes("row1");
1084    final byte[] row2 = Bytes.toBytes("row2");
1085    byte[] qualifier = Bytes.toBytes("qf1");
1086    Put put = new Put(row1);
1087
1088    // Adding KeyValue with the same row
1089    KeyValue kv = new KeyValue(row1, CONTENTS_FAMILY, qualifier, value);
1090    boolean ok = true;
1091    try {
1092      put.add(kv);
1093    } catch (IOException e) {
1094      ok = false;
1095    }
1096    assertTrue(ok);
1097
1098    // Adding KeyValue with the different row
1099    kv = new KeyValue(row2, CONTENTS_FAMILY, qualifier, value);
1100    ok = false;
1101    try {
1102      put.add(kv);
1103    } catch (IOException e) {
1104      ok = true;
1105    }
1106    assertTrue(ok);
1107  }
1108
1109  /**
1110   * test for HBASE-737
1111   */
1112  @Test
1113  public void testHBase737() throws IOException {
1114    final byte[] FAM1 = Bytes.toBytes("fam1");
1115    final byte[] FAM2 = Bytes.toBytes("fam2");
1116    // Open table
1117    try (Table table = TEST_UTIL.createTable(name.getTableName(), new byte[][] { FAM1, FAM2 })) {
1118      // Insert some values
1119      Put put = new Put(ROW);
1120      put.addColumn(FAM1, Bytes.toBytes("letters"), Bytes.toBytes("abcdefg"));
1121      table.put(put);
1122      try {
1123        Thread.sleep(1000);
1124      } catch (InterruptedException i) {
1125        // ignore
1126      }
1127
1128      put = new Put(ROW);
1129      put.addColumn(FAM1, Bytes.toBytes("numbers"), Bytes.toBytes("123456"));
1130      table.put(put);
1131
1132      try {
1133        Thread.sleep(1000);
1134      } catch (InterruptedException i) {
1135        // ignore
1136      }
1137
1138      put = new Put(ROW);
1139      put.addColumn(FAM2, Bytes.toBytes("letters"), Bytes.toBytes("hijklmnop"));
1140      table.put(put);
1141
1142      long[] times = new long[3];
1143
1144      // First scan the memstore
1145
1146      Scan scan = new Scan();
1147      scan.addFamily(FAM1);
1148      scan.addFamily(FAM2);
1149      try (ResultScanner s = table.getScanner(scan)) {
1150        int index = 0;
1151        Result r;
1152        while ((r = s.next()) != null) {
1153          for (Cell key : r.rawCells()) {
1154            times[index++] = key.getTimestamp();
1155          }
1156        }
1157      }
1158      for (int i = 0; i < times.length - 1; i++) {
1159        for (int j = i + 1; j < times.length; j++) {
1160          assertTrue(times[j] > times[i]);
1161        }
1162      }
1163
1164      // Flush data to disk and try again
1165      TEST_UTIL.flush();
1166
1167      // Reset times
1168      Arrays.fill(times, 0);
1169
1170      try {
1171        Thread.sleep(1000);
1172      } catch (InterruptedException i) {
1173        // ignore
1174      }
1175      scan = new Scan();
1176      scan.addFamily(FAM1);
1177      scan.addFamily(FAM2);
1178      try (ResultScanner s = table.getScanner(scan)) {
1179        int index = 0;
1180        Result r = null;
1181        while ((r = s.next()) != null) {
1182          for (Cell key : r.rawCells()) {
1183            times[index++] = key.getTimestamp();
1184          }
1185        }
1186        for (int i = 0; i < times.length - 1; i++) {
1187          for (int j = i + 1; j < times.length; j++) {
1188            assertTrue(times[j] > times[i]);
1189          }
1190        }
1191      }
1192    }
1193  }
1194
1195  @Test
1196  public void testListTables() throws IOException {
1197    final String testTableName = name.getTableName().toString();
1198    final TableName tableName1 = TableName.valueOf(testTableName + "1");
1199    final TableName tableName2 = TableName.valueOf(testTableName + "2");
1200    final TableName tableName3 = TableName.valueOf(testTableName + "3");
1201    TableName[] tables = new TableName[] { tableName1, tableName2, tableName3 };
1202    for (TableName table : tables) {
1203      TEST_UTIL.createTable(table, FAMILY);
1204    }
1205    try (Admin admin = TEST_UTIL.getAdmin()) {
1206      List<TableDescriptor> ts = admin.listTableDescriptors();
1207      HashSet<TableDescriptor> result = new HashSet<>(ts);
1208      int size = result.size();
1209      assertTrue(size >= tables.length);
1210      for (TableName table : tables) {
1211        boolean found = false;
1212        for (TableDescriptor t : ts) {
1213          if (t.getTableName().equals(table)) {
1214            found = true;
1215            break;
1216          }
1217        }
1218        assertTrue("Not found: " + table, found);
1219      }
1220    }
1221  }
1222
1223  /**
1224   * simple test that just executes parts of the client API that accept a pre-created Connection
1225   * instance
1226   */
1227  @Test
1228  public void testUnmanagedHConnection() throws IOException {
1229    final TableName tableName = name.getTableName();
1230    TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY);
1231    try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
1232      Table t = conn.getTable(tableName); Admin admin = conn.getAdmin()) {
1233      assertTrue(admin.tableExists(tableName));
1234      assertTrue(t.get(new Get(ROW)).isEmpty());
1235    }
1236  }
1237
1238  /**
1239   * test of that unmanaged HConnections are able to reconnect properly (see HBASE-5058)
1240   */
1241  @Test
1242  public void testUnmanagedHConnectionReconnect() throws Exception {
1243    Configuration conf = TEST_UTIL.getConfiguration();
1244    Class registryImpl = conf.getClass(HConstants.CLIENT_CONNECTION_REGISTRY_IMPL_CONF_KEY,
1245      ZKConnectionRegistry.class);
1246    // This test does not make sense for MasterRegistry since it stops the only master in the
1247    // cluster and starts a new master without populating the underlying config for the connection.
1248    Assume.assumeFalse(registryImpl.equals(MasterRegistry.class));
1249    final TableName tableName = name.getTableName();
1250    TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY);
1251    try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) {
1252      try (Table t = conn.getTable(tableName); Admin admin = conn.getAdmin()) {
1253        assertTrue(admin.tableExists(tableName));
1254        assertTrue(t.get(new Get(ROW)).isEmpty());
1255      }
1256
1257      // stop the master
1258      SingleProcessHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
1259      cluster.stopMaster(0, false);
1260      cluster.waitOnMaster(0);
1261
1262      // start up a new master
1263      cluster.startMaster();
1264      assertTrue(cluster.waitForActiveAndReadyMaster());
1265
1266      // test that the same unmanaged connection works with a new
1267      // Admin and can connect to the new master;
1268      try (Admin admin = conn.getAdmin()) {
1269        assertTrue(admin.tableExists(tableName));
1270        assertEquals(
1271          admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS)).getLiveServerMetrics().size(),
1272          SLAVES);
1273      }
1274    }
1275  }
1276
1277  @Test
1278  public void testMiscHTableStuff() throws IOException {
1279    final String testTableName = name.getTableName().toString();
1280    final TableName tableAname = TableName.valueOf(testTableName + "A");
1281    final TableName tableBname = TableName.valueOf(testTableName + "B");
1282    final byte[] attrName = Bytes.toBytes("TESTATTR");
1283    final byte[] attrValue = Bytes.toBytes("somevalue");
1284    byte[] value = Bytes.toBytes("value");
1285
1286    try (Table a = TEST_UTIL.createTable(tableAname, HConstants.CATALOG_FAMILY);
1287      Table b = TEST_UTIL.createTable(tableBname, HConstants.CATALOG_FAMILY)) {
1288      Put put = new Put(ROW);
1289      put.addColumn(HConstants.CATALOG_FAMILY, null, value);
1290      a.put(put);
1291
1292      // open a new connection to A and a connection to b
1293      try (Table newA = TEST_UTIL.getConnection().getTable(tableAname)) {
1294
1295        // copy data from A to B
1296        Scan scan = new Scan();
1297        scan.addFamily(HConstants.CATALOG_FAMILY);
1298        try (ResultScanner s = newA.getScanner(scan)) {
1299          for (Result r : s) {
1300            put = new Put(r.getRow());
1301            put.setDurability(Durability.SKIP_WAL);
1302            for (Cell kv : r.rawCells()) {
1303              put.add(kv);
1304            }
1305            b.put(put);
1306          }
1307        }
1308      }
1309
1310      // Opening a new connection to A will cause the tables to be reloaded
1311      try (Table anotherA = TEST_UTIL.getConnection().getTable(tableAname)) {
1312        Get get = new Get(ROW);
1313        get.addFamily(HConstants.CATALOG_FAMILY);
1314        anotherA.get(get);
1315      }
1316
1317      // We can still access A through newA because it has the table information
1318      // cached. And if it needs to recalibrate, that will cause the information
1319      // to be reloaded.
1320
1321      // Test user metadata
1322      Admin admin = TEST_UTIL.getAdmin();
1323      // make a modifiable descriptor
1324      TableDescriptor desc = a.getDescriptor();
1325      // offline the table
1326      admin.disableTable(tableAname);
1327      // add a user attribute to HTD
1328      TableDescriptorBuilder builder =
1329        TableDescriptorBuilder.newBuilder(desc).setValue(attrName, attrValue);
1330      // add a user attribute to HCD
1331      for (ColumnFamilyDescriptor c : desc.getColumnFamilies()) {
1332        builder.modifyColumnFamily(
1333          ColumnFamilyDescriptorBuilder.newBuilder(c).setValue(attrName, attrValue).build());
1334      }
1335      // update metadata for all regions of this table
1336      admin.modifyTable(builder.build());
1337      // enable the table
1338      admin.enableTable(tableAname);
1339
1340      // Test that attribute changes were applied
1341      desc = a.getDescriptor();
1342      assertEquals("wrong table descriptor returned", desc.getTableName(), tableAname);
1343      // check HTD attribute
1344      value = desc.getValue(attrName);
1345      assertNotNull("missing HTD attribute value", value);
1346      assertFalse("HTD attribute value is incorrect", Bytes.compareTo(value, attrValue) != 0);
1347      // check HCD attribute
1348      for (ColumnFamilyDescriptor c : desc.getColumnFamilies()) {
1349        value = c.getValue(attrName);
1350        assertNotNull("missing HCD attribute value", value);
1351        assertFalse("HCD attribute value is incorrect", Bytes.compareTo(value, attrValue) != 0);
1352      }
1353    }
1354  }
1355}