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.assertArrayEquals;
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertFalse;
023import static org.junit.Assert.assertNotNull;
024import static org.junit.Assert.assertNull;
025import static org.junit.Assert.assertTrue;
026import static org.junit.Assert.fail;
027import java.io.IOException;
028import java.util.ArrayList;
029import java.util.Arrays;
030import java.util.Collection;
031import java.util.LinkedList;
032import java.util.List;
033import java.util.Map;
034import java.util.NavigableMap;
035import java.util.concurrent.Callable;
036import java.util.concurrent.ExecutorService;
037import java.util.concurrent.Executors;
038import java.util.concurrent.atomic.AtomicReference;
039import org.apache.commons.lang3.ArrayUtils;
040import org.apache.hadoop.conf.Configuration;
041import org.apache.hadoop.fs.Path;
042import org.apache.hadoop.hbase.Cell;
043import org.apache.hadoop.hbase.CellScanner;
044import org.apache.hadoop.hbase.CellUtil;
045import org.apache.hadoop.hbase.CompareOperator;
046import org.apache.hadoop.hbase.DoNotRetryIOException;
047import org.apache.hadoop.hbase.HBaseClassTestRule;
048import org.apache.hadoop.hbase.HConstants;
049import org.apache.hadoop.hbase.HRegionLocation;
050import org.apache.hadoop.hbase.KeyValue;
051import org.apache.hadoop.hbase.PrivateCellUtil;
052import org.apache.hadoop.hbase.ServerName;
053import org.apache.hadoop.hbase.TableName;
054import org.apache.hadoop.hbase.TableNameTestRule;
055import org.apache.hadoop.hbase.Waiter;
056import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
057import org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint;
058import org.apache.hadoop.hbase.filter.BinaryComparator;
059import org.apache.hadoop.hbase.filter.Filter;
060import org.apache.hadoop.hbase.filter.FilterList;
061import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
062import org.apache.hadoop.hbase.filter.InclusiveStopFilter;
063import org.apache.hadoop.hbase.filter.KeyOnlyFilter;
064import org.apache.hadoop.hbase.filter.QualifierFilter;
065import org.apache.hadoop.hbase.filter.RegexStringComparator;
066import org.apache.hadoop.hbase.filter.RowFilter;
067import org.apache.hadoop.hbase.filter.SubstringComparator;
068import org.apache.hadoop.hbase.filter.ValueFilter;
069import org.apache.hadoop.hbase.io.TimeRange;
070import org.apache.hadoop.hbase.io.hfile.BlockCache;
071import org.apache.hadoop.hbase.io.hfile.CacheConfig;
072import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
073import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
074import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
075import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType;
076import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MultiRowMutationService;
077import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MutateRowsRequest;
078import org.apache.hadoop.hbase.regionserver.HRegion;
079import org.apache.hadoop.hbase.regionserver.HRegionServer;
080import org.apache.hadoop.hbase.regionserver.HStore;
081import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException;
082import org.apache.hadoop.hbase.testclassification.ClientTests;
083import org.apache.hadoop.hbase.testclassification.LargeTests;
084import org.apache.hadoop.hbase.util.Bytes;
085import org.apache.hadoop.hbase.util.CommonFSUtils;
086import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
087import org.apache.hadoop.hbase.util.FSUtils;
088import org.junit.AfterClass;
089import org.junit.ClassRule;
090import org.junit.Ignore;
091import org.junit.Rule;
092import org.junit.Test;
093import org.junit.experimental.categories.Category;
094import org.junit.runner.RunWith;
095import org.junit.runners.Parameterized;
096import org.slf4j.Logger;
097import org.slf4j.LoggerFactory;
098
099/**
100 * Run tests that use the HBase clients; {@link Table}.
101 * Sets up the HBase mini cluster once at start and runs through all client tests.
102 * Each creates a table named for the method and does its stuff against that.
103 *
104 * Parameterized to run with different registry implementations.
105 */
106@Category({LargeTests.class, ClientTests.class})
107@SuppressWarnings ("deprecation")
108@RunWith(Parameterized.class)
109public class TestFromClientSide5 extends FromClientSideBase {
110  private static final Logger LOG = LoggerFactory.getLogger(TestFromClientSide5.class);
111
112  @ClassRule
113  public static final HBaseClassTestRule CLASS_RULE =
114      HBaseClassTestRule.forClass(TestFromClientSide5.class);
115  @Rule
116  public TableNameTestRule name = new TableNameTestRule();
117
118  // To keep the child classes happy.
119  TestFromClientSide5() {}
120
121  public TestFromClientSide5(Class registry, int numHedgedReqs) throws Exception {
122    initialize(registry, numHedgedReqs, MultiRowMutationEndpoint.class);
123  }
124
125  @Parameterized.Parameters
126  public static Collection parameters() {
127    return Arrays.asList(new Object[][] {
128        { MasterRegistry.class, 1},
129        { MasterRegistry.class, 2},
130        { ZKConnectionRegistry.class, 1}
131    });
132  }
133
134  @AfterClass public static void tearDownAfterClass() throws Exception {
135    afterClass();
136  }
137
138  @Test
139  public void testGetClosestRowBefore() throws IOException, InterruptedException {
140    final TableName tableName = name.getTableName();
141    final byte[] firstRow = Bytes.toBytes("row111");
142    final byte[] secondRow = Bytes.toBytes("row222");
143    final byte[] thirdRow = Bytes.toBytes("row333");
144    final byte[] forthRow = Bytes.toBytes("row444");
145    final byte[] beforeFirstRow = Bytes.toBytes("row");
146    final byte[] beforeSecondRow = Bytes.toBytes("row22");
147    final byte[] beforeThirdRow = Bytes.toBytes("row33");
148    final byte[] beforeForthRow = Bytes.toBytes("row44");
149
150    try (Table table =
151        TEST_UTIL.createTable(tableName,
152          new byte[][] { HConstants.CATALOG_FAMILY, Bytes.toBytes("info2") }, 1, 1024);
153      RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
154
155      // set block size to 64 to making 2 kvs into one block, bypassing the walkForwardInSingleRow
156      // in Store.rowAtOrBeforeFromStoreFile
157      String regionName = locator.getAllRegionLocations().get(0).getRegion().getEncodedName();
158      HRegion region = TEST_UTIL.getRSForFirstRegionInTable(tableName).getRegion(regionName);
159      Put put1 = new Put(firstRow);
160      Put put2 = new Put(secondRow);
161      Put put3 = new Put(thirdRow);
162      Put put4 = new Put(forthRow);
163      byte[] one = new byte[] { 1 };
164      byte[] two = new byte[] { 2 };
165      byte[] three = new byte[] { 3 };
166      byte[] four = new byte[] { 4 };
167
168      put1.addColumn(HConstants.CATALOG_FAMILY, null, one);
169      put2.addColumn(HConstants.CATALOG_FAMILY, null, two);
170      put3.addColumn(HConstants.CATALOG_FAMILY, null, three);
171      put4.addColumn(HConstants.CATALOG_FAMILY, null, four);
172      table.put(put1);
173      table.put(put2);
174      table.put(put3);
175      table.put(put4);
176      region.flush(true);
177
178      Result result;
179
180      // Test before first that null is returned
181      result = getReverseScanResult(table, beforeFirstRow);
182      assertNull(result);
183
184      // Test at first that first is returned
185      result = getReverseScanResult(table, firstRow);
186      assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null));
187      assertTrue(Bytes.equals(result.getRow(), firstRow));
188      assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), one));
189
190      // Test in between first and second that first is returned
191      result = getReverseScanResult(table, beforeSecondRow);
192      assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null));
193      assertTrue(Bytes.equals(result.getRow(), firstRow));
194      assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), one));
195
196      // Test at second make sure second is returned
197      result = getReverseScanResult(table, secondRow);
198      assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null));
199      assertTrue(Bytes.equals(result.getRow(), secondRow));
200      assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), two));
201
202      // Test in second and third, make sure second is returned
203      result = getReverseScanResult(table, beforeThirdRow);
204      assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null));
205      assertTrue(Bytes.equals(result.getRow(), secondRow));
206      assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), two));
207
208      // Test at third make sure third is returned
209      result = getReverseScanResult(table, thirdRow);
210      assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null));
211      assertTrue(Bytes.equals(result.getRow(), thirdRow));
212      assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), three));
213
214      // Test in third and forth, make sure third is returned
215      result = getReverseScanResult(table, beforeForthRow);
216      assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null));
217      assertTrue(Bytes.equals(result.getRow(), thirdRow));
218      assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), three));
219
220      // Test at forth make sure forth is returned
221      result = getReverseScanResult(table, forthRow);
222      assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null));
223      assertTrue(Bytes.equals(result.getRow(), forthRow));
224      assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), four));
225
226      // Test after forth make sure forth is returned
227      result = getReverseScanResult(table, Bytes.add(forthRow, one));
228      assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null));
229      assertTrue(Bytes.equals(result.getRow(), forthRow));
230      assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), four));
231    }
232  }
233
234  private Result getReverseScanResult(Table table, byte[] row) throws IOException {
235    Scan scan = new Scan(row);
236    scan.setSmall(true);
237    scan.setReversed(true);
238    scan.setCaching(1);
239    scan.addFamily(HConstants.CATALOG_FAMILY);
240    try (ResultScanner scanner = table.getScanner(scan)) {
241      return scanner.next();
242    }
243  }
244
245  /**
246   * For HBASE-2156
247   */
248  @Test
249  public void testScanVariableReuse() {
250    Scan scan = new Scan();
251    scan.addFamily(FAMILY);
252    scan.addColumn(FAMILY, ROW);
253
254    assertEquals(1, scan.getFamilyMap().get(FAMILY).size());
255
256    scan = new Scan();
257    scan.addFamily(FAMILY);
258
259    assertNull(scan.getFamilyMap().get(FAMILY));
260    assertTrue(scan.getFamilyMap().containsKey(FAMILY));
261  }
262
263  @Test
264  public void testMultiRowMutation() throws Exception {
265    LOG.info("Starting testMultiRowMutation");
266    final TableName tableName = name.getTableName();
267    final byte [] ROW1 = Bytes.toBytes("testRow1");
268
269    try (Table t = TEST_UTIL.createTable(tableName, FAMILY)) {
270      Put p = new Put(ROW);
271      p.addColumn(FAMILY, QUALIFIER, VALUE);
272      MutationProto m1 = ProtobufUtil.toMutation(MutationType.PUT, p);
273
274      p = new Put(ROW1);
275      p.addColumn(FAMILY, QUALIFIER, VALUE);
276      MutationProto m2 = ProtobufUtil.toMutation(MutationType.PUT, p);
277
278      MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder();
279      mrmBuilder.addMutationRequest(m1);
280      mrmBuilder.addMutationRequest(m2);
281      MutateRowsRequest mrm = mrmBuilder.build();
282      CoprocessorRpcChannel channel = t.coprocessorService(ROW);
283      MultiRowMutationService.BlockingInterface service =
284              MultiRowMutationService.newBlockingStub(channel);
285      service.mutateRows(null, mrm);
286      Get g = new Get(ROW);
287      Result r = t.get(g);
288      assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIER)));
289      g = new Get(ROW1);
290      r = t.get(g);
291      assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIER)));
292    }
293  }
294
295  @Test
296  public void testRowMutation() throws Exception {
297    LOG.info("Starting testRowMutation");
298    final TableName tableName = name.getTableName();
299    try (Table t = TEST_UTIL.createTable(tableName, FAMILY)) {
300      byte[][] QUALIFIERS = new byte[][] { Bytes.toBytes("a"), Bytes.toBytes("b") };
301      RowMutations arm = new RowMutations(ROW);
302      Put p = new Put(ROW);
303      p.addColumn(FAMILY, QUALIFIERS[0], VALUE);
304      arm.add(p);
305      t.mutateRow(arm);
306
307      Get g = new Get(ROW);
308      Result r = t.get(g);
309      assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[0])));
310
311      arm = new RowMutations(ROW);
312      p = new Put(ROW);
313      p.addColumn(FAMILY, QUALIFIERS[1], VALUE);
314      arm.add(p);
315      Delete d = new Delete(ROW);
316      d.addColumns(FAMILY, QUALIFIERS[0]);
317      arm.add(d);
318      // TODO: Trying mutateRow again. The batch was failing with a one try only.
319      t.mutateRow(arm);
320      r = t.get(g);
321      assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[1])));
322      assertNull(r.getValue(FAMILY, QUALIFIERS[0]));
323
324      // Test that we get a region level exception
325      try {
326        arm = new RowMutations(ROW);
327        p = new Put(ROW);
328        p.addColumn(new byte[] { 'b', 'o', 'g', 'u', 's' }, QUALIFIERS[0], VALUE);
329        arm.add(p);
330        t.mutateRow(arm);
331        fail("Expected NoSuchColumnFamilyException");
332      } catch (NoSuchColumnFamilyException e) {
333        return;
334      } catch (RetriesExhaustedWithDetailsException e) {
335        for (Throwable rootCause : e.getCauses()) {
336          if (rootCause instanceof NoSuchColumnFamilyException) {
337            return;
338          }
339        }
340        throw e;
341      }
342    }
343  }
344
345  @Test
346  public void testBatchAppendWithReturnResultFalse() throws Exception {
347    LOG.info("Starting testBatchAppendWithReturnResultFalse");
348    final TableName tableName = name.getTableName();
349    try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) {
350      Append append1 = new Append(Bytes.toBytes("row1"));
351      append1.setReturnResults(false);
352      append1.addColumn(FAMILY, Bytes.toBytes("f1"), Bytes.toBytes("value1"));
353      Append append2 = new Append(Bytes.toBytes("row1"));
354      append2.setReturnResults(false);
355      append2.addColumn(FAMILY, Bytes.toBytes("f1"), Bytes.toBytes("value2"));
356      List<Append> appends = new ArrayList<>();
357      appends.add(append1);
358      appends.add(append2);
359      Object[] results = new Object[2];
360      table.batch(appends, results);
361      assertEquals(2, results.length);
362      for (Object r : results) {
363        Result result = (Result) r;
364        assertTrue(result.isEmpty());
365      }
366    }
367  }
368
369  @Test
370  public void testAppend() throws Exception {
371    LOG.info("Starting testAppend");
372    final TableName tableName = name.getTableName();
373    try (Table t = TEST_UTIL.createTable(tableName, FAMILY)) {
374      byte[] v1 = Bytes.toBytes("42");
375      byte[] v2 = Bytes.toBytes("23");
376      byte[][] QUALIFIERS = new byte[][]{
377              Bytes.toBytes("b"), Bytes.toBytes("a"), Bytes.toBytes("c")
378      };
379      Append a = new Append(ROW);
380      a.addColumn(FAMILY, QUALIFIERS[0], v1);
381      a.addColumn(FAMILY, QUALIFIERS[1], v2);
382      a.setReturnResults(false);
383      assertEmptyResult(t.append(a));
384
385      a = new Append(ROW);
386      a.addColumn(FAMILY, QUALIFIERS[0], v2);
387      a.addColumn(FAMILY, QUALIFIERS[1], v1);
388      a.addColumn(FAMILY, QUALIFIERS[2], v2);
389      Result r = t.append(a);
390      assertEquals(0, Bytes.compareTo(Bytes.add(v1, v2), r.getValue(FAMILY, QUALIFIERS[0])));
391      assertEquals(0, Bytes.compareTo(Bytes.add(v2, v1), r.getValue(FAMILY, QUALIFIERS[1])));
392      // QUALIFIERS[2] previously not exist, verify both value and timestamp are correct
393      assertEquals(0, Bytes.compareTo(v2, r.getValue(FAMILY, QUALIFIERS[2])));
394      assertEquals(r.getColumnLatestCell(FAMILY, QUALIFIERS[0]).getTimestamp(),
395              r.getColumnLatestCell(FAMILY, QUALIFIERS[2]).getTimestamp());
396    }
397  }
398  private List<Result> doAppend(final boolean walUsed) throws IOException {
399    LOG.info("Starting testAppend, walUsed is " + walUsed);
400    final TableName TABLENAME =
401            TableName.valueOf(walUsed ? "testAppendWithWAL" : "testAppendWithoutWAL");
402    try (Table t = TEST_UTIL.createTable(TABLENAME, FAMILY)) {
403      final byte[] row1 = Bytes.toBytes("c");
404      final byte[] row2 = Bytes.toBytes("b");
405      final byte[] row3 = Bytes.toBytes("a");
406      final byte[] qual = Bytes.toBytes("qual");
407      Put put_0 = new Put(row2);
408      put_0.addColumn(FAMILY, qual, Bytes.toBytes("put"));
409      Put put_1 = new Put(row3);
410      put_1.addColumn(FAMILY, qual, Bytes.toBytes("put"));
411      Append append_0 = new Append(row1);
412      append_0.addColumn(FAMILY, qual, Bytes.toBytes("i"));
413      Append append_1 = new Append(row1);
414      append_1.addColumn(FAMILY, qual, Bytes.toBytes("k"));
415      Append append_2 = new Append(row1);
416      append_2.addColumn(FAMILY, qual, Bytes.toBytes("e"));
417      if (!walUsed) {
418        append_2.setDurability(Durability.SKIP_WAL);
419      }
420      Append append_3 = new Append(row1);
421      append_3.addColumn(FAMILY, qual, Bytes.toBytes("a"));
422      Scan s = new Scan();
423      s.setCaching(1);
424      t.append(append_0);
425      t.put(put_0);
426      t.put(put_1);
427      List<Result> results = new LinkedList<>();
428      try (ResultScanner scanner = t.getScanner(s)) {
429        t.append(append_1);
430        t.append(append_2);
431        t.append(append_3);
432        for (Result r : scanner) {
433          results.add(r);
434        }
435      }
436      TEST_UTIL.deleteTable(TABLENAME);
437      return results;
438    }
439  }
440
441  @Test
442  public void testAppendWithoutWAL() throws Exception {
443    List<Result> resultsWithWal = doAppend(true);
444    List<Result> resultsWithoutWal = doAppend(false);
445    assertEquals(resultsWithWal.size(), resultsWithoutWal.size());
446    for (int i = 0; i != resultsWithWal.size(); ++i) {
447      Result resultWithWal = resultsWithWal.get(i);
448      Result resultWithoutWal = resultsWithoutWal.get(i);
449      assertEquals(resultWithWal.rawCells().length, resultWithoutWal.rawCells().length);
450      for (int j = 0; j != resultWithWal.rawCells().length; ++j) {
451        Cell cellWithWal = resultWithWal.rawCells()[j];
452        Cell cellWithoutWal = resultWithoutWal.rawCells()[j];
453        assertArrayEquals(CellUtil.cloneRow(cellWithWal), CellUtil.cloneRow(cellWithoutWal));
454        assertArrayEquals(CellUtil.cloneFamily(cellWithWal), CellUtil.cloneFamily(cellWithoutWal));
455        assertArrayEquals(CellUtil.cloneQualifier(cellWithWal),
456          CellUtil.cloneQualifier(cellWithoutWal));
457        assertArrayEquals(CellUtil.cloneValue(cellWithWal), CellUtil.cloneValue(cellWithoutWal));
458      }
459    }
460  }
461
462  @Test
463  public void testClientPoolRoundRobin() throws IOException {
464    final TableName tableName = name.getTableName();
465
466    int poolSize = 3;
467    int numVersions = poolSize * 2;
468    Configuration conf = TEST_UTIL.getConfiguration();
469    conf.set(HConstants.HBASE_CLIENT_IPC_POOL_TYPE, "round-robin");
470    conf.setInt(HConstants.HBASE_CLIENT_IPC_POOL_SIZE, poolSize);
471
472    try (Table table =
473                 TEST_UTIL.createTable(tableName, new byte[][] { FAMILY }, Integer.MAX_VALUE)) {
474
475      final long ts = EnvironmentEdgeManager.currentTime();
476      Get get = new Get(ROW);
477      get.addColumn(FAMILY, QUALIFIER);
478      get.readAllVersions();
479
480      for (int versions = 1; versions <= numVersions; versions++) {
481        Put put = new Put(ROW);
482        put.addColumn(FAMILY, QUALIFIER, ts + versions, VALUE);
483        table.put(put);
484
485        Result result = table.get(get);
486        NavigableMap<Long, byte[]> navigableMap = result.getMap().get(FAMILY)
487                .get(QUALIFIER);
488
489        assertEquals("The number of versions of '" + Bytes.toString(FAMILY) + ":"
490                + Bytes.toString(QUALIFIER) + " did not match", versions, navigableMap.size());
491        for (Map.Entry<Long, byte[]> entry : navigableMap.entrySet()) {
492          assertTrue("The value at time " + entry.getKey()
493                          + " did not match what was put",
494                  Bytes.equals(VALUE, entry.getValue()));
495        }
496      }
497    }
498  }
499
500  @Ignore ("Flakey: HBASE-8989") @Test
501  public void testClientPoolThreadLocal() throws IOException {
502    final TableName tableName = name.getTableName();
503
504    int poolSize = Integer.MAX_VALUE;
505    int numVersions = 3;
506    Configuration conf = TEST_UTIL.getConfiguration();
507    conf.set(HConstants.HBASE_CLIENT_IPC_POOL_TYPE, "thread-local");
508    conf.setInt(HConstants.HBASE_CLIENT_IPC_POOL_SIZE, poolSize);
509
510    try (final Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY },  3)) {
511
512      final long ts = EnvironmentEdgeManager.currentTime();
513      final Get get = new Get(ROW);
514      get.addColumn(FAMILY, QUALIFIER);
515      get.readAllVersions();
516
517      for (int versions = 1; versions <= numVersions; versions++) {
518        Put put = new Put(ROW);
519        put.addColumn(FAMILY, QUALIFIER, ts + versions, VALUE);
520        table.put(put);
521
522        Result result = table.get(get);
523        NavigableMap<Long, byte[]> navigableMap = result.getMap().get(FAMILY)
524                .get(QUALIFIER);
525
526        assertEquals("The number of versions of '" + Bytes.toString(FAMILY) + ":"
527                + Bytes.toString(QUALIFIER) + " did not match", versions, navigableMap.size());
528        for (Map.Entry<Long, byte[]> entry : navigableMap.entrySet()) {
529          assertTrue("The value at time " + entry.getKey()
530                          + " did not match what was put",
531                  Bytes.equals(VALUE, entry.getValue()));
532        }
533      }
534
535      final Object waitLock = new Object();
536      ExecutorService executorService = Executors.newFixedThreadPool(numVersions);
537      final AtomicReference<AssertionError> error = new AtomicReference<>(null);
538      for (int versions = numVersions; versions < numVersions * 2; versions++) {
539        final int versionsCopy = versions;
540        executorService.submit((Callable<Void>) () -> {
541          try {
542            Put put = new Put(ROW);
543            put.addColumn(FAMILY, QUALIFIER, ts + versionsCopy, VALUE);
544            table.put(put);
545
546            Result result = table.get(get);
547            NavigableMap<Long, byte[]> navigableMap = result.getMap()
548                    .get(FAMILY).get(QUALIFIER);
549
550            assertEquals("The number of versions of '" + Bytes.toString(FAMILY) + ":"
551                    + Bytes.toString(QUALIFIER) + " did not match " + versionsCopy, versionsCopy,
552                    navigableMap.size());
553            for (Map.Entry<Long, byte[]> entry : navigableMap.entrySet()) {
554              assertTrue("The value at time " + entry.getKey()
555                              + " did not match what was put",
556                      Bytes.equals(VALUE, entry.getValue()));
557            }
558            synchronized (waitLock) {
559              waitLock.wait();
560            }
561          } catch (Exception ignored) {
562          } catch (AssertionError e) {
563            // the error happens in a thread, it won't fail the test,
564            // need to pass it to the caller for proper handling.
565            error.set(e);
566            LOG.error(e.toString(), e);
567          }
568
569          return null;
570        });
571      }
572      synchronized (waitLock) {
573        waitLock.notifyAll();
574      }
575      executorService.shutdownNow();
576      assertNull(error.get());
577    }
578  }
579
580  @Test
581  public void testCheckAndPut() throws IOException {
582    final byte [] anotherrow = Bytes.toBytes("anotherrow");
583    final byte [] value2 = Bytes.toBytes("abcd");
584
585    try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) {
586      Put put1 = new Put(ROW);
587      put1.addColumn(FAMILY, QUALIFIER, VALUE);
588
589      // row doesn't exist, so using non-null value should be considered "not match".
590      boolean ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
591              .ifEquals(VALUE).thenPut(put1);
592      assertFalse(ok);
593
594      // row doesn't exist, so using "ifNotExists" should be considered "match".
595      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put1);
596      assertTrue(ok);
597
598      // row now exists, so using "ifNotExists" should be considered "not match".
599      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put1);
600      assertFalse(ok);
601
602      Put put2 = new Put(ROW);
603      put2.addColumn(FAMILY, QUALIFIER, value2);
604
605      // row now exists, use the matching value to check
606      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifEquals(VALUE).thenPut(put2);
607      assertTrue(ok);
608
609      Put put3 = new Put(anotherrow);
610      put3.addColumn(FAMILY, QUALIFIER, VALUE);
611
612      // try to do CheckAndPut on different rows
613      try {
614        table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifEquals(value2).thenPut(put3);
615        fail("trying to check and modify different rows should have failed.");
616      } catch (Exception ignored) {
617      }
618    }
619  }
620
621  @Test
622  public void testCheckAndMutateWithTimeRange() throws IOException {
623    try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) {
624      final long ts = System.currentTimeMillis() / 2;
625      Put put = new Put(ROW);
626      put.addColumn(FAMILY, QUALIFIER, ts, VALUE);
627
628      boolean ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
629              .ifNotExists()
630              .thenPut(put);
631      assertTrue(ok);
632
633      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
634              .timeRange(TimeRange.at(ts + 10000))
635              .ifEquals(VALUE)
636              .thenPut(put);
637      assertFalse(ok);
638
639      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
640              .timeRange(TimeRange.from(ts + 10000))
641              .ifEquals(VALUE)
642              .thenPut(put);
643      assertFalse(ok);
644
645      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
646              .timeRange(TimeRange.between(ts + 10000, ts + 20000))
647              .ifEquals(VALUE)
648              .thenPut(put);
649      assertFalse(ok);
650
651      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
652              .timeRange(TimeRange.until(ts))
653              .ifEquals(VALUE)
654              .thenPut(put);
655      assertFalse(ok);
656
657      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
658              .timeRange(TimeRange.at(ts))
659              .ifEquals(VALUE)
660              .thenPut(put);
661      assertTrue(ok);
662
663      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
664              .timeRange(TimeRange.from(ts))
665              .ifEquals(VALUE)
666              .thenPut(put);
667      assertTrue(ok);
668
669      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
670              .timeRange(TimeRange.between(ts, ts + 20000))
671              .ifEquals(VALUE)
672              .thenPut(put);
673      assertTrue(ok);
674
675      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
676              .timeRange(TimeRange.until(ts + 10000))
677              .ifEquals(VALUE)
678              .thenPut(put);
679      assertTrue(ok);
680
681      RowMutations rm = new RowMutations(ROW)
682              .add((Mutation) put);
683      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
684              .timeRange(TimeRange.at(ts + 10000))
685              .ifEquals(VALUE)
686              .thenMutate(rm);
687      assertFalse(ok);
688
689      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
690              .timeRange(TimeRange.at(ts))
691              .ifEquals(VALUE)
692              .thenMutate(rm);
693      assertTrue(ok);
694
695      Delete delete = new Delete(ROW)
696              .addColumn(FAMILY, QUALIFIER);
697
698      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
699              .timeRange(TimeRange.at(ts + 10000))
700              .ifEquals(VALUE)
701              .thenDelete(delete);
702      assertFalse(ok);
703
704      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
705              .timeRange(TimeRange.at(ts))
706              .ifEquals(VALUE)
707              .thenDelete(delete);
708      assertTrue(ok);
709    }
710  }
711
712  @Test
713  public void testCheckAndPutWithCompareOp() throws IOException {
714    final byte [] value1 = Bytes.toBytes("aaaa");
715    final byte [] value2 = Bytes.toBytes("bbbb");
716    final byte [] value3 = Bytes.toBytes("cccc");
717    final byte [] value4 = Bytes.toBytes("dddd");
718
719    try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) {
720
721      Put put2 = new Put(ROW);
722      put2.addColumn(FAMILY, QUALIFIER, value2);
723
724      Put put3 = new Put(ROW);
725      put3.addColumn(FAMILY, QUALIFIER, value3);
726
727      // row doesn't exist, so using "ifNotExists" should be considered "match".
728      boolean ok =
729              table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put2);
730      assertTrue(ok);
731
732      // cell = "bbbb", using "aaaa" to compare only LESS/LESS_OR_EQUAL/NOT_EQUAL
733      // turns out "match"
734      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
735              .ifMatches(CompareOperator.GREATER, value1).thenPut(put2);
736      assertFalse(ok);
737      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
738              .ifMatches(CompareOperator.EQUAL, value1).thenPut(put2);
739      assertFalse(ok);
740      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
741              .ifMatches(CompareOperator.GREATER_OR_EQUAL, value1).thenPut(put2);
742      assertFalse(ok);
743      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
744              .ifMatches(CompareOperator.LESS, value1).thenPut(put2);
745      assertTrue(ok);
746      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
747              .ifMatches(CompareOperator.LESS_OR_EQUAL, value1).thenPut(put2);
748      assertTrue(ok);
749      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
750              .ifMatches(CompareOperator.NOT_EQUAL, value1).thenPut(put3);
751      assertTrue(ok);
752
753      // cell = "cccc", using "dddd" to compare only LARGER/LARGER_OR_EQUAL/NOT_EQUAL
754      // turns out "match"
755      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
756              .ifMatches(CompareOperator.LESS, value4).thenPut(put3);
757      assertFalse(ok);
758      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
759              .ifMatches(CompareOperator.LESS_OR_EQUAL, value4).thenPut(put3);
760      assertFalse(ok);
761      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
762              .ifMatches(CompareOperator.EQUAL, value4).thenPut(put3);
763      assertFalse(ok);
764      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
765              .ifMatches(CompareOperator.GREATER, value4).thenPut(put3);
766      assertTrue(ok);
767      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
768              .ifMatches(CompareOperator.GREATER_OR_EQUAL, value4).thenPut(put3);
769      assertTrue(ok);
770      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
771              .ifMatches(CompareOperator.NOT_EQUAL, value4).thenPut(put2);
772      assertTrue(ok);
773
774      // cell = "bbbb", using "bbbb" to compare only GREATER_OR_EQUAL/LESS_OR_EQUAL/EQUAL
775      // turns out "match"
776      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
777              .ifMatches(CompareOperator.GREATER, value2).thenPut(put2);
778      assertFalse(ok);
779      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
780              .ifMatches(CompareOperator.NOT_EQUAL, value2).thenPut(put2);
781      assertFalse(ok);
782      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
783              .ifMatches(CompareOperator.LESS, value2).thenPut(put2);
784      assertFalse(ok);
785      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
786              .ifMatches(CompareOperator.GREATER_OR_EQUAL, value2).thenPut(put2);
787      assertTrue(ok);
788      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
789              .ifMatches(CompareOperator.LESS_OR_EQUAL, value2).thenPut(put2);
790      assertTrue(ok);
791      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
792              .ifMatches(CompareOperator.EQUAL, value2).thenPut(put3);
793      assertTrue(ok);
794    }
795  }
796
797  @Test
798  public void testCheckAndDelete() throws IOException {
799    final byte [] value1 = Bytes.toBytes("aaaa");
800
801    try (Table table = TEST_UTIL.createTable(name.getTableName(),
802        FAMILY)) {
803
804      Put put = new Put(ROW);
805      put.addColumn(FAMILY, QUALIFIER, value1);
806      table.put(put);
807
808      Delete delete = new Delete(ROW);
809      delete.addColumns(FAMILY, QUALIFIER);
810
811      boolean ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
812              .ifEquals(value1).thenDelete(delete);
813      assertTrue(ok);
814    }
815  }
816
817  @Test
818  public void testCheckAndDeleteWithCompareOp() throws IOException {
819    final byte [] value1 = Bytes.toBytes("aaaa");
820    final byte [] value2 = Bytes.toBytes("bbbb");
821    final byte [] value3 = Bytes.toBytes("cccc");
822    final byte [] value4 = Bytes.toBytes("dddd");
823
824    try (Table table = TEST_UTIL.createTable(name.getTableName(),
825        FAMILY)) {
826
827      Put put2 = new Put(ROW);
828      put2.addColumn(FAMILY, QUALIFIER, value2);
829      table.put(put2);
830
831      Put put3 = new Put(ROW);
832      put3.addColumn(FAMILY, QUALIFIER, value3);
833
834      Delete delete = new Delete(ROW);
835      delete.addColumns(FAMILY, QUALIFIER);
836
837      // cell = "bbbb", using "aaaa" to compare only LESS/LESS_OR_EQUAL/NOT_EQUAL
838      // turns out "match"
839      boolean ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
840              .ifMatches(CompareOperator.GREATER, value1).thenDelete(delete);
841      assertFalse(ok);
842      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
843              .ifMatches(CompareOperator.EQUAL, value1).thenDelete(delete);
844      assertFalse(ok);
845      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
846              .ifMatches(CompareOperator.GREATER_OR_EQUAL, value1).thenDelete(delete);
847      assertFalse(ok);
848      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
849              .ifMatches(CompareOperator.LESS, value1).thenDelete(delete);
850      assertTrue(ok);
851      table.put(put2);
852      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
853              .ifMatches(CompareOperator.LESS_OR_EQUAL, value1).thenDelete(delete);
854      assertTrue(ok);
855      table.put(put2);
856      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
857              .ifMatches(CompareOperator.NOT_EQUAL, value1).thenDelete(delete);
858      assertTrue(ok);
859
860      // cell = "cccc", using "dddd" to compare only LARGER/LARGER_OR_EQUAL/NOT_EQUAL
861      // turns out "match"
862      table.put(put3);
863      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
864              .ifMatches(CompareOperator.LESS, value4).thenDelete(delete);
865      assertFalse(ok);
866      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
867              .ifMatches(CompareOperator.LESS_OR_EQUAL, value4).thenDelete(delete);
868      assertFalse(ok);
869      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
870              .ifMatches(CompareOperator.EQUAL, value4).thenDelete(delete);
871      assertFalse(ok);
872      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
873              .ifMatches(CompareOperator.GREATER, value4).thenDelete(delete);
874      assertTrue(ok);
875      table.put(put3);
876      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
877              .ifMatches(CompareOperator.GREATER_OR_EQUAL, value4).thenDelete(delete);
878      assertTrue(ok);
879      table.put(put3);
880      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
881              .ifMatches(CompareOperator.NOT_EQUAL, value4).thenDelete(delete);
882      assertTrue(ok);
883
884      // cell = "bbbb", using "bbbb" to compare only GREATER_OR_EQUAL/LESS_OR_EQUAL/EQUAL
885      // turns out "match"
886      table.put(put2);
887      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
888              .ifMatches(CompareOperator.GREATER, value2).thenDelete(delete);
889      assertFalse(ok);
890      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
891              .ifMatches(CompareOperator.NOT_EQUAL, value2).thenDelete(delete);
892      assertFalse(ok);
893      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
894              .ifMatches(CompareOperator.LESS, value2).thenDelete(delete);
895      assertFalse(ok);
896      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
897              .ifMatches(CompareOperator.GREATER_OR_EQUAL, value2).thenDelete(delete);
898      assertTrue(ok);
899      table.put(put2);
900      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
901              .ifMatches(CompareOperator.LESS_OR_EQUAL, value2).thenDelete(delete);
902      assertTrue(ok);
903      table.put(put2);
904      ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER)
905              .ifMatches(CompareOperator.EQUAL, value2).thenDelete(delete);
906      assertTrue(ok);
907    }
908  }
909
910  /**
911  * Test ScanMetrics
912  */
913  @Test
914  @SuppressWarnings({"unused", "checkstyle:EmptyBlock"})
915  public void testScanMetrics() throws Exception {
916    final TableName tableName = name.getTableName();
917
918    // Set up test table:
919    // Create table:
920    try (Table ht = TEST_UTIL.createMultiRegionTable(tableName, FAMILY)) {
921      int numOfRegions;
922      try (RegionLocator r = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
923        numOfRegions = r.getStartKeys().length;
924      }
925      // Create 3 rows in the table, with rowkeys starting with "zzz*" so that
926      // scan are forced to hit all the regions.
927      Put put1 = new Put(Bytes.toBytes("zzz1"));
928      put1.addColumn(FAMILY, QUALIFIER, VALUE);
929      Put put2 = new Put(Bytes.toBytes("zzz2"));
930      put2.addColumn(FAMILY, QUALIFIER, VALUE);
931      Put put3 = new Put(Bytes.toBytes("zzz3"));
932      put3.addColumn(FAMILY, QUALIFIER, VALUE);
933      ht.put(Arrays.asList(put1, put2, put3));
934
935      Scan scan1 = new Scan();
936      int numRecords = 0;
937      try (ResultScanner scanner = ht.getScanner(scan1)) {
938        for (Result result : scanner) {
939          numRecords++;
940        }
941
942        LOG.info("test data has " + numRecords + " records.");
943
944        // by default, scan metrics collection is turned off
945        assertNull(scanner.getScanMetrics());
946      }
947
948      // turn on scan metrics
949      Scan scan2 = new Scan();
950      scan2.setScanMetricsEnabled(true);
951      scan2.setCaching(numRecords + 1);
952      try (ResultScanner scanner = ht.getScanner(scan2)) {
953        for (Result result : scanner.next(numRecords - 1)) {
954        }
955        scanner.close();
956        // closing the scanner will set the metrics.
957        assertNotNull(scanner.getScanMetrics());
958      }
959
960      // set caching to 1, because metrics are collected in each roundtrip only
961      scan2 = new Scan();
962      scan2.setScanMetricsEnabled(true);
963      scan2.setCaching(1);
964      try (ResultScanner scanner = ht.getScanner(scan2)) {
965        // per HBASE-5717, this should still collect even if you don't run all the way to
966        // the end of the scanner. So this is asking for 2 of the 3 rows we inserted.
967        for (Result result : scanner.next(numRecords - 1)) {
968        }
969        ScanMetrics scanMetrics = scanner.getScanMetrics();
970        assertEquals("Did not access all the regions in the table", numOfRegions,
971                scanMetrics.countOfRegions.get());
972      }
973
974      // check byte counters
975      scan2 = new Scan();
976      scan2.setScanMetricsEnabled(true);
977      scan2.setCaching(1);
978      try (ResultScanner scanner = ht.getScanner(scan2)) {
979        int numBytes = 0;
980        for (Result result : scanner.next(1)) {
981          for (Cell cell : result.listCells()) {
982            numBytes += PrivateCellUtil.estimatedSerializedSizeOf(cell);
983          }
984        }
985        scanner.close();
986        ScanMetrics scanMetrics = scanner.getScanMetrics();
987        assertEquals("Did not count the result bytes", numBytes,
988                scanMetrics.countOfBytesInResults.get());
989      }
990
991      // check byte counters on a small scan
992      scan2 = new Scan();
993      scan2.setScanMetricsEnabled(true);
994      scan2.setCaching(1);
995      scan2.setSmall(true);
996      try (ResultScanner scanner = ht.getScanner(scan2)) {
997        int numBytes = 0;
998        for (Result result : scanner.next(1)) {
999          for (Cell cell : result.listCells()) {
1000            numBytes += PrivateCellUtil.estimatedSerializedSizeOf(cell);
1001          }
1002        }
1003        scanner.close();
1004        ScanMetrics scanMetrics = scanner.getScanMetrics();
1005        assertEquals("Did not count the result bytes", numBytes,
1006                scanMetrics.countOfBytesInResults.get());
1007      }
1008
1009      // now, test that the metrics are still collected even if you don't call close, but do
1010      // run past the end of all the records
1011      /** There seems to be a timing issue here.  Comment out for now. Fix when time.
1012       Scan scanWithoutClose = new Scan();
1013       scanWithoutClose.setCaching(1);
1014       scanWithoutClose.setScanMetricsEnabled(true);
1015       ResultScanner scannerWithoutClose = ht.getScanner(scanWithoutClose);
1016       for (Result result : scannerWithoutClose.next(numRecords + 1)) {
1017       }
1018       ScanMetrics scanMetricsWithoutClose = getScanMetrics(scanWithoutClose);
1019       assertEquals("Did not access all the regions in the table", numOfRegions,
1020       scanMetricsWithoutClose.countOfRegions.get());
1021       */
1022
1023      // finally,
1024      // test that the metrics are collected correctly if you both run past all the records,
1025      // AND close the scanner
1026      Scan scanWithClose = new Scan();
1027      // make sure we can set caching up to the number of a scanned values
1028      scanWithClose.setCaching(numRecords);
1029      scanWithClose.setScanMetricsEnabled(true);
1030      try (ResultScanner scannerWithClose = ht.getScanner(scanWithClose)) {
1031        for (Result result : scannerWithClose.next(numRecords + 1)) {
1032        }
1033        scannerWithClose.close();
1034        ScanMetrics scanMetricsWithClose = scannerWithClose.getScanMetrics();
1035        assertEquals("Did not access all the regions in the table", numOfRegions,
1036                scanMetricsWithClose.countOfRegions.get());
1037      }
1038    }
1039  }
1040
1041  /**
1042   * Tests that cache on write works all the way up from the client-side.
1043   *
1044   * Performs inserts, flushes, and compactions, verifying changes in the block
1045   * cache along the way.
1046   */
1047  @Test
1048  public void testCacheOnWriteEvictOnClose() throws Exception {
1049    final TableName tableName = name.getTableName();
1050    byte [] data = Bytes.toBytes("data");
1051    try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) {
1052      try (RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
1053        // get the block cache and region
1054        String regionName = locator.getAllRegionLocations().get(0).getRegion().getEncodedName();
1055
1056        HRegion region = TEST_UTIL.getRSForFirstRegionInTable(tableName)
1057                .getRegion(regionName);
1058        HStore store = region.getStores().iterator().next();
1059        CacheConfig cacheConf = store.getCacheConfig();
1060        cacheConf.setCacheDataOnWrite(true);
1061        cacheConf.setEvictOnClose(true);
1062        BlockCache cache = cacheConf.getBlockCache().get();
1063
1064        // establish baseline stats
1065        long startBlockCount = cache.getBlockCount();
1066        long startBlockHits = cache.getStats().getHitCount();
1067        long startBlockMiss = cache.getStats().getMissCount();
1068
1069        // wait till baseline is stable, (minimal 500 ms)
1070        for (int i = 0; i < 5; i++) {
1071          Thread.sleep(100);
1072          if (startBlockCount != cache.getBlockCount()
1073                  || startBlockHits != cache.getStats().getHitCount()
1074                  || startBlockMiss != cache.getStats().getMissCount()) {
1075            startBlockCount = cache.getBlockCount();
1076            startBlockHits = cache.getStats().getHitCount();
1077            startBlockMiss = cache.getStats().getMissCount();
1078            i = -1;
1079          }
1080        }
1081
1082        // insert data
1083        Put put = new Put(ROW);
1084        put.addColumn(FAMILY, QUALIFIER, data);
1085        table.put(put);
1086        assertTrue(Bytes.equals(table.get(new Get(ROW)).value(), data));
1087
1088        // data was in memstore so don't expect any changes
1089        assertEquals(startBlockCount, cache.getBlockCount());
1090        assertEquals(startBlockHits, cache.getStats().getHitCount());
1091        assertEquals(startBlockMiss, cache.getStats().getMissCount());
1092
1093        // flush the data
1094        LOG.debug("Flushing cache");
1095        region.flush(true);
1096
1097        // expect two more blocks in cache - DATA and ROOT_INDEX
1098        // , no change in hits/misses
1099        long expectedBlockCount = startBlockCount + 2;
1100        long expectedBlockHits = startBlockHits;
1101        long expectedBlockMiss = startBlockMiss;
1102        assertEquals(expectedBlockCount, cache.getBlockCount());
1103        assertEquals(expectedBlockHits, cache.getStats().getHitCount());
1104        assertEquals(expectedBlockMiss, cache.getStats().getMissCount());
1105        // read the data and expect same blocks, one new hit, no misses
1106        assertTrue(Bytes.equals(table.get(new Get(ROW)).value(), data));
1107        assertEquals(expectedBlockCount, cache.getBlockCount());
1108        assertEquals(++expectedBlockHits, cache.getStats().getHitCount());
1109        assertEquals(expectedBlockMiss, cache.getStats().getMissCount());
1110        // insert a second column, read the row, no new blocks, one new hit
1111        byte[] QUALIFIER2 = Bytes.add(QUALIFIER, QUALIFIER);
1112        byte[] data2 = Bytes.add(data, data);
1113        put = new Put(ROW);
1114        put.addColumn(FAMILY, QUALIFIER2, data2);
1115        table.put(put);
1116        Result r = table.get(new Get(ROW));
1117        assertTrue(Bytes.equals(r.getValue(FAMILY, QUALIFIER), data));
1118        assertTrue(Bytes.equals(r.getValue(FAMILY, QUALIFIER2), data2));
1119        assertEquals(expectedBlockCount, cache.getBlockCount());
1120        assertEquals(++expectedBlockHits, cache.getStats().getHitCount());
1121        assertEquals(expectedBlockMiss, cache.getStats().getMissCount());
1122        // flush, one new block
1123        System.out.println("Flushing cache");
1124        region.flush(true);
1125
1126        // + 1 for Index Block, +1 for data block
1127        expectedBlockCount += 2;
1128        assertEquals(expectedBlockCount, cache.getBlockCount());
1129        assertEquals(expectedBlockHits, cache.getStats().getHitCount());
1130        assertEquals(expectedBlockMiss, cache.getStats().getMissCount());
1131        // compact, net minus two blocks, two hits, no misses
1132        System.out.println("Compacting");
1133        assertEquals(2, store.getStorefilesCount());
1134        store.triggerMajorCompaction();
1135        region.compact(true);
1136        store.closeAndArchiveCompactedFiles();
1137        waitForStoreFileCount(store, 1, 10000); // wait 10 seconds max
1138        assertEquals(1, store.getStorefilesCount());
1139        // evicted two data blocks and two index blocks and compaction does not cache new blocks
1140        expectedBlockCount = 0;
1141        assertEquals(expectedBlockCount, cache.getBlockCount());
1142        expectedBlockHits += 2;
1143        assertEquals(expectedBlockMiss, cache.getStats().getMissCount());
1144        assertEquals(expectedBlockHits, cache.getStats().getHitCount());
1145        // read the row, this should be a cache miss because we don't cache data
1146        // blocks on compaction
1147        r = table.get(new Get(ROW));
1148        assertTrue(Bytes.equals(r.getValue(FAMILY, QUALIFIER), data));
1149        assertTrue(Bytes.equals(r.getValue(FAMILY, QUALIFIER2), data2));
1150        expectedBlockCount += 1; // cached one data block
1151        assertEquals(expectedBlockCount, cache.getBlockCount());
1152        assertEquals(expectedBlockHits, cache.getStats().getHitCount());
1153        assertEquals(++expectedBlockMiss, cache.getStats().getMissCount());
1154      }
1155    }
1156  }
1157
1158  private void waitForStoreFileCount(HStore store, int count, int timeout)
1159      throws InterruptedException {
1160    long start = System.currentTimeMillis();
1161    while (start + timeout > System.currentTimeMillis() && store.getStorefilesCount() != count) {
1162      Thread.sleep(100);
1163    }
1164    System.out.println("start=" + start + ", now=" + System.currentTimeMillis() + ", cur=" +
1165        store.getStorefilesCount());
1166    assertEquals(count, store.getStorefilesCount());
1167  }
1168
1169  /**
1170   * Tests the non cached version of getRegionLocator by moving a region.
1171   */
1172  @Test
1173  public void testNonCachedGetRegionLocation() throws Exception {
1174    // Test Initialization.
1175    final TableName tableName = name.getTableName();
1176    byte [] family1 = Bytes.toBytes("f1");
1177    byte [] family2 = Bytes.toBytes("f2");
1178    try (Table ignored = TEST_UTIL.createTable(tableName, new byte[][] {family1, family2}, 10);
1179        Admin admin = TEST_UTIL.getAdmin();
1180        RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
1181      List<HRegionLocation> allRegionLocations = locator.getAllRegionLocations();
1182      assertEquals(1, allRegionLocations.size());
1183      RegionInfo regionInfo = allRegionLocations.get(0).getRegion();
1184      ServerName addrBefore = allRegionLocations.get(0).getServerName();
1185      // Verify region location before move.
1186      HRegionLocation addrCache = locator.getRegionLocation(regionInfo.getStartKey(), false);
1187      HRegionLocation addrNoCache = locator.getRegionLocation(regionInfo.getStartKey(),  true);
1188
1189      assertEquals(addrBefore.getPort(), addrCache.getPort());
1190      assertEquals(addrBefore.getPort(), addrNoCache.getPort());
1191
1192      // Make sure more than one server.
1193      if (TEST_UTIL.getMiniHBaseCluster().getLiveRegionServerThreads().size() <= 1) {
1194        TEST_UTIL.getMiniHBaseCluster().startRegionServer();
1195        Waiter.waitFor(TEST_UTIL.getConfiguration(), 30000, new Waiter.Predicate<Exception>() {
1196          @Override public boolean evaluate() throws Exception {
1197            return TEST_UTIL.getMiniHBaseCluster().getLiveRegionServerThreads().size() > 1;
1198          }
1199        });
1200      }
1201
1202      ServerName addrAfter = null;
1203      // Now move the region to a different server.
1204      for (int i = 0; i < TEST_UTIL.getMiniHBaseCluster().getLiveRegionServerThreads().size();
1205           i++) {
1206        HRegionServer regionServer = TEST_UTIL.getHBaseCluster().getRegionServer(i);
1207        ServerName addr = regionServer.getServerName();
1208        if (addr.getPort() != addrBefore.getPort()) {
1209          admin.move(regionInfo.getEncodedNameAsBytes(), addr);
1210          // Wait for the region to move.
1211          Thread.sleep(5000);
1212          addrAfter = addr;
1213          break;
1214        }
1215      }
1216
1217      // Verify the region was moved.
1218      addrCache = locator.getRegionLocation(regionInfo.getStartKey(), false);
1219      addrNoCache = locator.getRegionLocation(regionInfo.getStartKey(), true);
1220      assertNotNull(addrAfter);
1221      assertTrue(addrAfter.getPort() != addrCache.getPort());
1222      assertEquals(addrAfter.getPort(), addrNoCache.getPort());
1223    }
1224  }
1225
1226  /**
1227   * Tests getRegionsInRange by creating some regions over which a range of
1228   * keys spans; then changing the key range.
1229   */
1230  @Test
1231  public void testGetRegionsInRange() throws Exception {
1232    // Test Initialization.
1233    byte [] startKey = Bytes.toBytes("ddc");
1234    byte [] endKey = Bytes.toBytes("mmm");
1235    TableName tableName = name.getTableName();
1236    TEST_UTIL.createMultiRegionTable(tableName, new byte[][] { FAMILY }, 10);
1237
1238    int numOfRegions;
1239    try (RegionLocator r = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
1240      numOfRegions = r.getStartKeys().length;
1241    }
1242    assertEquals(26, numOfRegions);
1243
1244    // Get the regions in this range
1245    List<HRegionLocation> regionsList = getRegionsInRange(tableName, startKey, endKey);
1246    assertEquals(10, regionsList.size());
1247
1248    // Change the start key
1249    startKey = Bytes.toBytes("fff");
1250    regionsList = getRegionsInRange(tableName, startKey, endKey);
1251    assertEquals(7, regionsList.size());
1252
1253    // Change the end key
1254    endKey = Bytes.toBytes("nnn");
1255    regionsList = getRegionsInRange(tableName, startKey, endKey);
1256    assertEquals(8, regionsList.size());
1257
1258    // Empty start key
1259    regionsList = getRegionsInRange(tableName, HConstants.EMPTY_START_ROW, endKey);
1260    assertEquals(13, regionsList.size());
1261
1262    // Empty end key
1263    regionsList = getRegionsInRange(tableName, startKey, HConstants.EMPTY_END_ROW);
1264    assertEquals(21, regionsList.size());
1265
1266    // Both start and end keys empty
1267    regionsList = getRegionsInRange(tableName, HConstants.EMPTY_START_ROW,
1268        HConstants.EMPTY_END_ROW);
1269    assertEquals(26, regionsList.size());
1270
1271    // Change the end key to somewhere in the last block
1272    endKey = Bytes.toBytes("zzz1");
1273    regionsList = getRegionsInRange(tableName, startKey, endKey);
1274    assertEquals(21, regionsList.size());
1275
1276    // Change the start key to somewhere in the first block
1277    startKey = Bytes.toBytes("aac");
1278    regionsList = getRegionsInRange(tableName, startKey, endKey);
1279    assertEquals(26, regionsList.size());
1280
1281    // Make start and end key the same
1282    startKey = Bytes.toBytes("ccc");
1283    endKey = Bytes.toBytes("ccc");
1284    regionsList = getRegionsInRange(tableName, startKey, endKey);
1285    assertEquals(1, regionsList.size());
1286  }
1287
1288  private List<HRegionLocation> getRegionsInRange(TableName tableName, byte[] startKey,
1289      byte[] endKey) throws IOException {
1290    List<HRegionLocation> regionsInRange = new ArrayList<>();
1291    byte[] currentKey = startKey;
1292    final boolean endKeyIsEndOfTable = Bytes.equals(endKey, HConstants.EMPTY_END_ROW);
1293    try (RegionLocator r = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
1294      do {
1295        HRegionLocation regionLocation = r.getRegionLocation(currentKey);
1296        regionsInRange.add(regionLocation);
1297        currentKey = regionLocation.getRegion().getEndKey();
1298      } while (!Bytes.equals(currentKey, HConstants.EMPTY_END_ROW)
1299          && (endKeyIsEndOfTable || Bytes.compareTo(currentKey, endKey) < 0));
1300      return regionsInRange;
1301    }
1302  }
1303
1304  @Test
1305  public void testJira6912() throws Exception {
1306    final TableName tableName = name.getTableName();
1307    try (Table foo = TEST_UTIL.createTable(tableName, new byte[][] {FAMILY}, 10)) {
1308
1309      List<Put> puts = new ArrayList<>();
1310      for (int i = 0; i != 100; i++) {
1311        Put put = new Put(Bytes.toBytes(i));
1312        put.addColumn(FAMILY, FAMILY, Bytes.toBytes(i));
1313        puts.add(put);
1314      }
1315      foo.put(puts);
1316      // If i comment this out it works
1317      TEST_UTIL.flush();
1318
1319      Scan scan = new Scan();
1320      scan.setStartRow(Bytes.toBytes(1));
1321      scan.setStopRow(Bytes.toBytes(3));
1322      scan.addColumn(FAMILY, FAMILY);
1323      scan.setFilter(new RowFilter(CompareOperator.NOT_EQUAL,
1324              new BinaryComparator(Bytes.toBytes(1))));
1325
1326      try (ResultScanner scanner = foo.getScanner(scan)) {
1327        Result[] bar = scanner.next(100);
1328        assertEquals(1, bar.length);
1329      }
1330    }
1331  }
1332
1333  @Test
1334  public void testScan_NullQualifier() throws IOException {
1335    try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) {
1336      Put put = new Put(ROW);
1337      put.addColumn(FAMILY, QUALIFIER, VALUE);
1338      table.put(put);
1339
1340      put = new Put(ROW);
1341      put.addColumn(FAMILY, null, VALUE);
1342      table.put(put);
1343      LOG.info("Row put");
1344
1345      Scan scan = new Scan();
1346      scan.addColumn(FAMILY, null);
1347
1348      ResultScanner scanner = table.getScanner(scan);
1349      Result[] bar = scanner.next(100);
1350      assertEquals(1, bar.length);
1351      assertEquals(1, bar[0].size());
1352
1353      scan = new Scan();
1354      scan.addFamily(FAMILY);
1355
1356      scanner = table.getScanner(scan);
1357      bar = scanner.next(100);
1358      assertEquals(1, bar.length);
1359      assertEquals(2, bar[0].size());
1360    }
1361  }
1362
1363  @Test
1364  public void testNegativeTimestamp() throws IOException {
1365    try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) {
1366
1367      try {
1368        Put put = new Put(ROW, -1);
1369        put.addColumn(FAMILY, QUALIFIER, VALUE);
1370        table.put(put);
1371        fail("Negative timestamps should not have been allowed");
1372      } catch (IllegalArgumentException ex) {
1373        assertTrue(ex.getMessage().contains("negative"));
1374      }
1375
1376      try {
1377        Put put = new Put(ROW);
1378        long ts = -1;
1379        put.addColumn(FAMILY, QUALIFIER, ts, VALUE);
1380        table.put(put);
1381        fail("Negative timestamps should not have been allowed");
1382      } catch (IllegalArgumentException ex) {
1383        assertTrue(ex.getMessage().contains("negative"));
1384      }
1385
1386      try {
1387        Delete delete = new Delete(ROW, -1);
1388        table.delete(delete);
1389        fail("Negative timestamps should not have been allowed");
1390      } catch (IllegalArgumentException ex) {
1391        assertTrue(ex.getMessage().contains("negative"));
1392      }
1393
1394      try {
1395        Delete delete = new Delete(ROW);
1396        delete.addFamily(FAMILY, -1);
1397        table.delete(delete);
1398        fail("Negative timestamps should not have been allowed");
1399      } catch (IllegalArgumentException ex) {
1400        assertTrue(ex.getMessage().contains("negative"));
1401      }
1402
1403      try {
1404        Scan scan = new Scan();
1405        scan.setTimeRange(-1, 1);
1406        table.getScanner(scan);
1407        fail("Negative timestamps should not have been allowed");
1408      } catch (IllegalArgumentException ex) {
1409        assertTrue(ex.getMessage().contains("negative"));
1410      }
1411
1412      // KeyValue should allow negative timestamps for backwards compat. Otherwise, if the user
1413      // already has negative timestamps in cluster data, HBase won't be able to handle that
1414      try {
1415        new KeyValue(Bytes.toBytes(42), Bytes.toBytes(42), Bytes.toBytes(42), -1,
1416                Bytes.toBytes(42));
1417      } catch (IllegalArgumentException ex) {
1418        fail("KeyValue SHOULD allow negative timestamps");
1419      }
1420
1421    }
1422  }
1423
1424  @Test
1425  public void testRawScanRespectsVersions() throws Exception {
1426    final TableName tableName = name.getTableName();
1427    try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) {
1428      byte[] row = Bytes.toBytes("row");
1429
1430      // put the same row 4 times, with different values
1431      Put p = new Put(row);
1432      p.addColumn(FAMILY, QUALIFIER, 10, VALUE);
1433      table.put(p);
1434      p = new Put(row);
1435      p.addColumn(FAMILY, QUALIFIER, 11, ArrayUtils.add(VALUE, (byte) 2));
1436      table.put(p);
1437
1438      p = new Put(row);
1439      p.addColumn(FAMILY, QUALIFIER, 12, ArrayUtils.add(VALUE, (byte) 3));
1440      table.put(p);
1441
1442      p = new Put(row);
1443      p.addColumn(FAMILY, QUALIFIER, 13, ArrayUtils.add(VALUE, (byte) 4));
1444      table.put(p);
1445
1446      int versions = 4;
1447      Scan s = new Scan(row);
1448      // get all the possible versions
1449      s.setMaxVersions();
1450      s.setRaw(true);
1451
1452      try (ResultScanner scanner = table.getScanner(s)) {
1453        int count = 0;
1454        for (Result r : scanner) {
1455          assertEquals("Found an unexpected number of results for the row!", versions,
1456                  r.listCells().size());
1457          count++;
1458        }
1459        assertEquals("Found more than a single row when raw scanning the table with a single row!",
1460                1, count);
1461      }
1462
1463      // then if we decrease the number of versions, but keep the scan raw, we should see exactly
1464      // that number of versions
1465      versions = 2;
1466      s.setMaxVersions(versions);
1467      try (ResultScanner scanner = table.getScanner(s)) {
1468        int count = 0;
1469        for (Result r : scanner) {
1470          assertEquals("Found an unexpected number of results for the row!", versions,
1471                  r.listCells().size());
1472          count++;
1473        }
1474        assertEquals("Found more than a single row when raw scanning the table with a single row!",
1475                1, count);
1476      }
1477
1478      // finally, if we turn off raw scanning, but max out the number of versions, we should go back
1479      // to seeing just three
1480      versions = 3;
1481      s.setMaxVersions(versions);
1482      try (ResultScanner scanner = table.getScanner(s)) {
1483        int count = 0;
1484        for (Result r : scanner) {
1485          assertEquals("Found an unexpected number of results for the row!", versions,
1486                  r.listCells().size());
1487          count++;
1488        }
1489        assertEquals("Found more than a single row when raw scanning the table with a single row!",
1490                1, count);
1491      }
1492
1493    }
1494    TEST_UTIL.deleteTable(tableName);
1495  }
1496
1497  @Test
1498  public void testEmptyFilterList() throws Exception {
1499    // Test Initialization.
1500    final TableName tableName = name.getTableName();
1501    try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) {
1502
1503      // Insert one row each region
1504      Put put = new Put(Bytes.toBytes("row"));
1505      put.addColumn(FAMILY, QUALIFIER, VALUE);
1506      table.put(put);
1507
1508      List<Result> scanResults = new LinkedList<>();
1509      Scan scan = new Scan();
1510      scan.setFilter(new FilterList());
1511      try (ResultScanner scanner = table.getScanner(scan)) {
1512        for (Result r : scanner) {
1513          scanResults.add(r);
1514        }
1515      }
1516      assertEquals(1, scanResults.size());
1517      Get g = new Get(Bytes.toBytes("row"));
1518      g.setFilter(new FilterList());
1519      Result getResult = table.get(g);
1520      Result scanResult = scanResults.get(0);
1521      assertEquals(scanResult.rawCells().length, getResult.rawCells().length);
1522      for (int i = 0; i != scanResult.rawCells().length; ++i) {
1523        Cell scanCell = scanResult.rawCells()[i];
1524        Cell getCell = getResult.rawCells()[i];
1525        assertEquals(0, Bytes.compareTo(CellUtil.cloneRow(scanCell),
1526                CellUtil.cloneRow(getCell)));
1527        assertEquals(0, Bytes.compareTo(CellUtil.cloneFamily(scanCell),
1528                CellUtil.cloneFamily(getCell)));
1529        assertEquals(0, Bytes.compareTo(CellUtil.cloneQualifier(scanCell),
1530                CellUtil.cloneQualifier(getCell)));
1531        assertEquals(0, Bytes.compareTo(CellUtil.cloneValue(scanCell),
1532                CellUtil.cloneValue(getCell)));
1533      }
1534    }
1535  }
1536
1537  @Test
1538  public void testSmallScan() throws Exception {
1539    // Test Initialization.
1540    final TableName tableName = name.getTableName();
1541    try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) {
1542
1543      // Insert one row each region
1544      int insertNum = 10;
1545      for (int i = 0; i < 10; i++) {
1546        Put put = new Put(Bytes.toBytes("row" + String.format("%03d", i)));
1547        put.addColumn(FAMILY, QUALIFIER, VALUE);
1548        table.put(put);
1549      }
1550
1551      // normal scan
1552      try (ResultScanner scanner = table.getScanner(new Scan())) {
1553        int count = 0;
1554        for (Result r : scanner) {
1555          assertFalse(r.isEmpty());
1556          count++;
1557        }
1558        assertEquals(insertNum, count);
1559      }
1560
1561      // small scan
1562      Scan scan = new Scan(HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW);
1563      scan.setSmall(true);
1564      scan.setCaching(2);
1565      try (ResultScanner scanner = table.getScanner(scan)) {
1566        int count = 0;
1567        for (Result r : scanner) {
1568          assertFalse(r.isEmpty());
1569          count++;
1570        }
1571        assertEquals(insertNum, count);
1572      }
1573    }
1574  }
1575
1576  @Test
1577  public void testSuperSimpleWithReverseScan() throws Exception {
1578    final TableName tableName = name.getTableName();
1579    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
1580      Put put = new Put(Bytes.toBytes("0-b11111-0000000000000000000"));
1581      put.addColumn(FAMILY, QUALIFIER, VALUE);
1582      ht.put(put);
1583      put = new Put(Bytes.toBytes("0-b11111-0000000000000000002"));
1584      put.addColumn(FAMILY, QUALIFIER, VALUE);
1585      ht.put(put);
1586      put = new Put(Bytes.toBytes("0-b11111-0000000000000000004"));
1587      put.addColumn(FAMILY, QUALIFIER, VALUE);
1588      ht.put(put);
1589      put = new Put(Bytes.toBytes("0-b11111-0000000000000000006"));
1590      put.addColumn(FAMILY, QUALIFIER, VALUE);
1591      ht.put(put);
1592      put = new Put(Bytes.toBytes("0-b11111-0000000000000000008"));
1593      put.addColumn(FAMILY, QUALIFIER, VALUE);
1594      ht.put(put);
1595      put = new Put(Bytes.toBytes("0-b22222-0000000000000000001"));
1596      put.addColumn(FAMILY, QUALIFIER, VALUE);
1597      ht.put(put);
1598      put = new Put(Bytes.toBytes("0-b22222-0000000000000000003"));
1599      put.addColumn(FAMILY, QUALIFIER, VALUE);
1600      ht.put(put);
1601      put = new Put(Bytes.toBytes("0-b22222-0000000000000000005"));
1602      put.addColumn(FAMILY, QUALIFIER, VALUE);
1603      ht.put(put);
1604      put = new Put(Bytes.toBytes("0-b22222-0000000000000000007"));
1605      put.addColumn(FAMILY, QUALIFIER, VALUE);
1606      ht.put(put);
1607      put = new Put(Bytes.toBytes("0-b22222-0000000000000000009"));
1608      put.addColumn(FAMILY, QUALIFIER, VALUE);
1609      ht.put(put);
1610      Scan scan = new Scan(Bytes.toBytes("0-b11111-9223372036854775807"),
1611              Bytes.toBytes("0-b11111-0000000000000000000"));
1612      scan.setReversed(true);
1613      try (ResultScanner scanner = ht.getScanner(scan)) {
1614        Result result = scanner.next();
1615        assertTrue(Bytes.equals(result.getRow(),
1616                Bytes.toBytes("0-b11111-0000000000000000008")));
1617      }
1618    }
1619  }
1620
1621  @Test
1622  public void testFiltersWithReverseScan() throws Exception {
1623    final TableName tableName = name.getTableName();
1624    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
1625      byte[][] ROWS = makeN(ROW, 10);
1626      byte[][] QUALIFIERS = {Bytes.toBytes("col0-<d2v1>-<d3v2>"),
1627              Bytes.toBytes("col1-<d2v1>-<d3v2>"),
1628              Bytes.toBytes("col2-<d2v1>-<d3v2>"),
1629              Bytes.toBytes("col3-<d2v1>-<d3v2>"),
1630              Bytes.toBytes("col4-<d2v1>-<d3v2>"),
1631              Bytes.toBytes("col5-<d2v1>-<d3v2>"),
1632              Bytes.toBytes("col6-<d2v1>-<d3v2>"),
1633              Bytes.toBytes("col7-<d2v1>-<d3v2>"),
1634              Bytes.toBytes("col8-<d2v1>-<d3v2>"),
1635              Bytes.toBytes("col9-<d2v1>-<d3v2>")};
1636      for (int i = 0; i < 10; i++) {
1637        Put put = new Put(ROWS[i]);
1638        put.addColumn(FAMILY, QUALIFIERS[i], VALUE);
1639        ht.put(put);
1640      }
1641      Scan scan = new Scan();
1642      scan.setReversed(true);
1643      scan.addFamily(FAMILY);
1644      Filter filter = new QualifierFilter(CompareOperator.EQUAL,
1645              new RegexStringComparator("col[1-5]"));
1646      scan.setFilter(filter);
1647      try (ResultScanner scanner = ht.getScanner(scan)) {
1648        int expectedIndex = 5;
1649        for (Result result : scanner) {
1650          assertEquals(1, result.size());
1651          Cell c = result.rawCells()[0];
1652          assertTrue(Bytes.equals(c.getRowArray(), c.getRowOffset(), c.getRowLength(),
1653                  ROWS[expectedIndex], 0, ROWS[expectedIndex].length));
1654          assertTrue(Bytes.equals(c.getQualifierArray(), c.getQualifierOffset(),
1655                  c.getQualifierLength(), QUALIFIERS[expectedIndex], 0,
1656                  QUALIFIERS[expectedIndex].length));
1657          expectedIndex--;
1658        }
1659        assertEquals(0, expectedIndex);
1660      }
1661    }
1662  }
1663
1664  @Test
1665  public void testKeyOnlyFilterWithReverseScan() throws Exception {
1666    final TableName tableName = name.getTableName();
1667    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
1668      byte[][] ROWS = makeN(ROW, 10);
1669      byte[][] QUALIFIERS = {Bytes.toBytes("col0-<d2v1>-<d3v2>"),
1670              Bytes.toBytes("col1-<d2v1>-<d3v2>"),
1671              Bytes.toBytes("col2-<d2v1>-<d3v2>"),
1672              Bytes.toBytes("col3-<d2v1>-<d3v2>"),
1673              Bytes.toBytes("col4-<d2v1>-<d3v2>"),
1674              Bytes.toBytes("col5-<d2v1>-<d3v2>"),
1675              Bytes.toBytes("col6-<d2v1>-<d3v2>"),
1676              Bytes.toBytes("col7-<d2v1>-<d3v2>"),
1677              Bytes.toBytes("col8-<d2v1>-<d3v2>"),
1678              Bytes.toBytes("col9-<d2v1>-<d3v2>")};
1679      for (int i = 0; i < 10; i++) {
1680        Put put = new Put(ROWS[i]);
1681        put.addColumn(FAMILY, QUALIFIERS[i], VALUE);
1682        ht.put(put);
1683      }
1684      Scan scan = new Scan();
1685      scan.setReversed(true);
1686      scan.addFamily(FAMILY);
1687      Filter filter = new KeyOnlyFilter(true);
1688      scan.setFilter(filter);
1689      try (ResultScanner ignored = ht.getScanner(scan)) {
1690        int count = 0;
1691        for (Result result : ht.getScanner(scan)) {
1692          assertEquals(1, result.size());
1693          assertEquals(Bytes.SIZEOF_INT, result.rawCells()[0].getValueLength());
1694          assertEquals(VALUE.length, Bytes.toInt(CellUtil.cloneValue(result.rawCells()[0])));
1695          count++;
1696        }
1697        assertEquals(10, count);
1698      }
1699    }
1700  }
1701
1702  /**
1703   * Test simple table and non-existent row cases.
1704   */
1705  @Test
1706  public void testSimpleMissingWithReverseScan() throws Exception {
1707    final TableName tableName = name.getTableName();
1708    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
1709      byte[][] ROWS = makeN(ROW, 4);
1710
1711      // Try to get a row on an empty table
1712      Scan scan = new Scan();
1713      scan.setReversed(true);
1714      Result result = getSingleScanResult(ht, scan);
1715      assertNullResult(result);
1716
1717      scan = new Scan(ROWS[0]);
1718      scan.setReversed(true);
1719      result = getSingleScanResult(ht, scan);
1720      assertNullResult(result);
1721
1722      scan = new Scan(ROWS[0], ROWS[1]);
1723      scan.setReversed(true);
1724      result = getSingleScanResult(ht, scan);
1725      assertNullResult(result);
1726
1727      scan = new Scan();
1728      scan.setReversed(true);
1729      scan.addFamily(FAMILY);
1730      result = getSingleScanResult(ht, scan);
1731      assertNullResult(result);
1732
1733      scan = new Scan();
1734      scan.setReversed(true);
1735      scan.addColumn(FAMILY, QUALIFIER);
1736      result = getSingleScanResult(ht, scan);
1737      assertNullResult(result);
1738
1739      // Insert a row
1740
1741      Put put = new Put(ROWS[2]);
1742      put.addColumn(FAMILY, QUALIFIER, VALUE);
1743      ht.put(put);
1744
1745      // Make sure we can scan the row
1746      scan = new Scan();
1747      scan.setReversed(true);
1748      result = getSingleScanResult(ht, scan);
1749      assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE);
1750
1751      scan = new Scan(ROWS[3], ROWS[0]);
1752      scan.setReversed(true);
1753      result = getSingleScanResult(ht, scan);
1754      assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE);
1755
1756      scan = new Scan(ROWS[2], ROWS[1]);
1757      scan.setReversed(true);
1758      result = getSingleScanResult(ht, scan);
1759      assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE);
1760
1761      // Try to scan empty rows around it
1762      // Introduced MemStore#shouldSeekForReverseScan to fix the following
1763      scan = new Scan(ROWS[1]);
1764      scan.setReversed(true);
1765      result = getSingleScanResult(ht, scan);
1766      assertNullResult(result);
1767    }
1768  }
1769
1770  @Test
1771  public void testNullWithReverseScan() throws Exception {
1772    final TableName tableName = name.getTableName();
1773    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
1774      // Null qualifier (should work)
1775      Put put = new Put(ROW);
1776      put.addColumn(FAMILY, null, VALUE);
1777      ht.put(put);
1778      scanTestNull(ht, ROW, FAMILY, VALUE, true);
1779      Delete delete = new Delete(ROW);
1780      delete.addColumns(FAMILY, null);
1781      ht.delete(delete);
1782    }
1783
1784    // Use a new table
1785    try (Table ht =
1786       TEST_UTIL.createTable(TableName.valueOf(name.getTableName().toString() + "2"), FAMILY)) {
1787      // Empty qualifier, byte[0] instead of null (should work)
1788      Put put = new Put(ROW);
1789      put.addColumn(FAMILY, HConstants.EMPTY_BYTE_ARRAY, VALUE);
1790      ht.put(put);
1791      scanTestNull(ht, ROW, FAMILY, VALUE, true);
1792      TEST_UTIL.flush();
1793      scanTestNull(ht, ROW, FAMILY, VALUE, true);
1794      Delete delete = new Delete(ROW);
1795      delete.addColumns(FAMILY, HConstants.EMPTY_BYTE_ARRAY);
1796      ht.delete(delete);
1797      // Null value
1798      put = new Put(ROW);
1799      put.addColumn(FAMILY, QUALIFIER, null);
1800      ht.put(put);
1801      Scan scan = new Scan();
1802      scan.setReversed(true);
1803      scan.addColumn(FAMILY, QUALIFIER);
1804      Result result = getSingleScanResult(ht, scan);
1805      assertSingleResult(result, ROW, FAMILY, QUALIFIER, null);
1806    }
1807  }
1808
1809  @Test
1810  @SuppressWarnings("checkstyle:MethodLength")
1811  public void testDeletesWithReverseScan() throws Exception {
1812    final TableName tableName = name.getTableName();
1813    byte[][] ROWS = makeNAscii(ROW, 6);
1814    byte[][] FAMILIES = makeNAscii(FAMILY, 3);
1815    byte[][] VALUES = makeN(VALUE, 5);
1816    long[] ts = { 1000, 2000, 3000, 4000, 5000 };
1817    try (Table ht = TEST_UTIL.createTable(tableName, FAMILIES, 3)) {
1818
1819      Put put = new Put(ROW);
1820      put.addColumn(FAMILIES[0], QUALIFIER, ts[0], VALUES[0]);
1821      put.addColumn(FAMILIES[0], QUALIFIER, ts[1], VALUES[1]);
1822      ht.put(put);
1823
1824      Delete delete = new Delete(ROW);
1825      delete.addFamily(FAMILIES[0], ts[0]);
1826      ht.delete(delete);
1827
1828      Scan scan = new Scan(ROW);
1829      scan.setReversed(true);
1830      scan.addFamily(FAMILIES[0]);
1831      scan.setMaxVersions(Integer.MAX_VALUE);
1832      Result result = getSingleScanResult(ht, scan);
1833      assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[]{ts[1]},
1834              new byte[][]{VALUES[1]}, 0, 0);
1835
1836      // Test delete latest version
1837      put = new Put(ROW);
1838      put.addColumn(FAMILIES[0], QUALIFIER, ts[4], VALUES[4]);
1839      put.addColumn(FAMILIES[0], QUALIFIER, ts[2], VALUES[2]);
1840      put.addColumn(FAMILIES[0], QUALIFIER, ts[3], VALUES[3]);
1841      put.addColumn(FAMILIES[0], null, ts[4], VALUES[4]);
1842      put.addColumn(FAMILIES[0], null, ts[2], VALUES[2]);
1843      put.addColumn(FAMILIES[0], null, ts[3], VALUES[3]);
1844      ht.put(put);
1845
1846      delete = new Delete(ROW);
1847      delete.addColumn(FAMILIES[0], QUALIFIER); // ts[4]
1848      ht.delete(delete);
1849
1850      scan = new Scan(ROW);
1851      scan.setReversed(true);
1852      scan.addColumn(FAMILIES[0], QUALIFIER);
1853      scan.setMaxVersions(Integer.MAX_VALUE);
1854      result = getSingleScanResult(ht, scan);
1855      assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[]{ts[1],
1856              ts[2], ts[3]}, new byte[][]{VALUES[1], VALUES[2], VALUES[3]}, 0, 2);
1857
1858      // Test for HBASE-1847
1859      delete = new Delete(ROW);
1860      delete.addColumn(FAMILIES[0], null);
1861      ht.delete(delete);
1862
1863      // Cleanup null qualifier
1864      delete = new Delete(ROW);
1865      delete.addColumns(FAMILIES[0], null);
1866      ht.delete(delete);
1867
1868      // Expected client behavior might be that you can re-put deleted values
1869      // But alas, this is not to be. We can't put them back in either case.
1870
1871      put = new Put(ROW);
1872      put.addColumn(FAMILIES[0], QUALIFIER, ts[0], VALUES[0]);
1873      put.addColumn(FAMILIES[0], QUALIFIER, ts[4], VALUES[4]);
1874      ht.put(put);
1875
1876      // The Scanner returns the previous values, the expected-naive-unexpected
1877      // behavior
1878
1879      scan = new Scan(ROW);
1880      scan.setReversed(true);
1881      scan.addFamily(FAMILIES[0]);
1882      scan.setMaxVersions(Integer.MAX_VALUE);
1883      result = getSingleScanResult(ht, scan);
1884      assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[]{ts[1],
1885              ts[2], ts[3]}, new byte[][]{VALUES[1], VALUES[2], VALUES[3]}, 0, 2);
1886
1887      // Test deleting an entire family from one row but not the other various
1888      // ways
1889
1890      put = new Put(ROWS[0]);
1891      put.addColumn(FAMILIES[1], QUALIFIER, ts[0], VALUES[0]);
1892      put.addColumn(FAMILIES[1], QUALIFIER, ts[1], VALUES[1]);
1893      put.addColumn(FAMILIES[2], QUALIFIER, ts[2], VALUES[2]);
1894      put.addColumn(FAMILIES[2], QUALIFIER, ts[3], VALUES[3]);
1895      ht.put(put);
1896
1897      put = new Put(ROWS[1]);
1898      put.addColumn(FAMILIES[1], QUALIFIER, ts[0], VALUES[0]);
1899      put.addColumn(FAMILIES[1], QUALIFIER, ts[1], VALUES[1]);
1900      put.addColumn(FAMILIES[2], QUALIFIER, ts[2], VALUES[2]);
1901      put.addColumn(FAMILIES[2], QUALIFIER, ts[3], VALUES[3]);
1902      ht.put(put);
1903
1904      put = new Put(ROWS[2]);
1905      put.addColumn(FAMILIES[1], QUALIFIER, ts[0], VALUES[0]);
1906      put.addColumn(FAMILIES[1], QUALIFIER, ts[1], VALUES[1]);
1907      put.addColumn(FAMILIES[2], QUALIFIER, ts[2], VALUES[2]);
1908      put.addColumn(FAMILIES[2], QUALIFIER, ts[3], VALUES[3]);
1909      ht.put(put);
1910
1911      delete = new Delete(ROWS[0]);
1912      delete.addFamily(FAMILIES[2]);
1913      ht.delete(delete);
1914
1915      delete = new Delete(ROWS[1]);
1916      delete.addColumns(FAMILIES[1], QUALIFIER);
1917      ht.delete(delete);
1918
1919      delete = new Delete(ROWS[2]);
1920      delete.addColumn(FAMILIES[1], QUALIFIER);
1921      delete.addColumn(FAMILIES[1], QUALIFIER);
1922      delete.addColumn(FAMILIES[2], QUALIFIER);
1923      ht.delete(delete);
1924
1925      scan = new Scan(ROWS[0]);
1926      scan.setReversed(true);
1927      scan.addFamily(FAMILIES[1]);
1928      scan.addFamily(FAMILIES[2]);
1929      scan.setMaxVersions(Integer.MAX_VALUE);
1930      result = getSingleScanResult(ht, scan);
1931      assertEquals("Expected 2 keys but received " + result.size(), 2, result.size());
1932      assertNResult(result, ROWS[0], FAMILIES[1], QUALIFIER, new long[]{ts[0],
1933              ts[1]}, new byte[][]{VALUES[0], VALUES[1]}, 0, 1);
1934
1935      scan = new Scan(ROWS[1]);
1936      scan.setReversed(true);
1937      scan.addFamily(FAMILIES[1]);
1938      scan.addFamily(FAMILIES[2]);
1939      scan.setMaxVersions(Integer.MAX_VALUE);
1940      result = getSingleScanResult(ht, scan);
1941      assertEquals("Expected 2 keys but received " + result.size(), 2, result.size());
1942
1943      scan = new Scan(ROWS[2]);
1944      scan.setReversed(true);
1945      scan.addFamily(FAMILIES[1]);
1946      scan.addFamily(FAMILIES[2]);
1947      scan.setMaxVersions(Integer.MAX_VALUE);
1948      result = getSingleScanResult(ht, scan);
1949      assertEquals(1, result.size());
1950      assertNResult(result, ROWS[2], FAMILIES[2], QUALIFIER,
1951              new long[]{ts[2]}, new byte[][]{VALUES[2]}, 0, 0);
1952
1953      // Test if we delete the family first in one row (HBASE-1541)
1954
1955      delete = new Delete(ROWS[3]);
1956      delete.addFamily(FAMILIES[1]);
1957      ht.delete(delete);
1958
1959      put = new Put(ROWS[3]);
1960      put.addColumn(FAMILIES[2], QUALIFIER, VALUES[0]);
1961      ht.put(put);
1962
1963      put = new Put(ROWS[4]);
1964      put.addColumn(FAMILIES[1], QUALIFIER, VALUES[1]);
1965      put.addColumn(FAMILIES[2], QUALIFIER, VALUES[2]);
1966      ht.put(put);
1967
1968      scan = new Scan(ROWS[4]);
1969      scan.setReversed(true);
1970      scan.addFamily(FAMILIES[1]);
1971      scan.addFamily(FAMILIES[2]);
1972      scan.setMaxVersions(Integer.MAX_VALUE);
1973      ResultScanner scanner = ht.getScanner(scan);
1974      result = scanner.next();
1975      assertEquals("Expected 2 keys but received " + result.size(), 2, result.size());
1976      assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[0]), ROWS[4]));
1977      assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[1]), ROWS[4]));
1978      assertTrue(Bytes.equals(CellUtil.cloneValue(result.rawCells()[0]), VALUES[1]));
1979      assertTrue(Bytes.equals(CellUtil.cloneValue(result.rawCells()[1]), VALUES[2]));
1980      result = scanner.next();
1981      assertEquals("Expected 1 key but received " + result.size(), 1, result.size());
1982      assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[0]), ROWS[3]));
1983      assertTrue(Bytes.equals(CellUtil.cloneValue(result.rawCells()[0]), VALUES[0]));
1984      scanner.close();
1985    }
1986  }
1987
1988  /**
1989   * Tests reversed scan under multi regions
1990   */
1991  @Test
1992  public void testReversedScanUnderMultiRegions() throws Exception {
1993    // Test Initialization.
1994    final TableName tableName = name.getTableName();
1995    byte[] maxByteArray = ConnectionUtils.MAX_BYTE_ARRAY;
1996    byte[][] splitRows = new byte[][] { Bytes.toBytes("005"),
1997        Bytes.add(Bytes.toBytes("005"), Bytes.multiple(maxByteArray, 16)),
1998        Bytes.toBytes("006"),
1999        Bytes.add(Bytes.toBytes("006"), Bytes.multiple(maxByteArray, 8)),
2000        Bytes.toBytes("007"),
2001        Bytes.add(Bytes.toBytes("007"), Bytes.multiple(maxByteArray, 4)),
2002        Bytes.toBytes("008"), Bytes.multiple(maxByteArray, 2) };
2003    try (Table table = TEST_UTIL.createTable(tableName, FAMILY, splitRows)) {
2004      TEST_UTIL.waitUntilAllRegionsAssigned(table.getName());
2005
2006      try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
2007        assertEquals(splitRows.length + 1, l.getAllRegionLocations().size());
2008      }
2009      // Insert one row each region
2010      int insertNum = splitRows.length;
2011      for (byte[] splitRow : splitRows) {
2012        Put put = new Put(splitRow);
2013        put.addColumn(FAMILY, QUALIFIER, VALUE);
2014        table.put(put);
2015      }
2016
2017      // scan forward
2018      try (ResultScanner scanner = table.getScanner(new Scan())) {
2019        int count = 0;
2020        for (Result r : scanner) {
2021          assertFalse(r.isEmpty());
2022          count++;
2023        }
2024        assertEquals(insertNum, count);
2025      }
2026
2027      // scan backward
2028      Scan scan = new Scan();
2029      scan.setReversed(true);
2030      try (ResultScanner scanner = table.getScanner(scan)) {
2031        int count = 0;
2032        byte[] lastRow = null;
2033        for (Result r : scanner) {
2034          assertFalse(r.isEmpty());
2035          count++;
2036          byte[] thisRow = r.getRow();
2037          if (lastRow != null) {
2038            assertTrue("Error scan order, last row= " + Bytes.toString(lastRow)
2039                            + ",this row=" + Bytes.toString(thisRow),
2040                    Bytes.compareTo(thisRow, lastRow) < 0);
2041          }
2042          lastRow = thisRow;
2043        }
2044        assertEquals(insertNum, count);
2045      }
2046    }
2047  }
2048
2049  /**
2050   * Tests reversed scan under multi regions
2051   */
2052  @Test
2053  public void testSmallReversedScanUnderMultiRegions() throws Exception {
2054    // Test Initialization.
2055    final TableName tableName = name.getTableName();
2056    byte[][] splitRows = new byte[][]{
2057        Bytes.toBytes("000"), Bytes.toBytes("002"), Bytes.toBytes("004"),
2058        Bytes.toBytes("006"), Bytes.toBytes("008"), Bytes.toBytes("010")};
2059    try (Table table = TEST_UTIL.createTable(tableName, FAMILY, splitRows)) {
2060      TEST_UTIL.waitUntilAllRegionsAssigned(table.getName());
2061
2062      try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
2063        assertEquals(splitRows.length + 1, l.getAllRegionLocations().size());
2064      }
2065      for (byte[] splitRow : splitRows) {
2066        Put put = new Put(splitRow);
2067        put.addColumn(FAMILY, QUALIFIER, VALUE);
2068        table.put(put);
2069
2070        byte[] nextRow = Bytes.copy(splitRow);
2071        nextRow[nextRow.length - 1]++;
2072
2073        put = new Put(nextRow);
2074        put.addColumn(FAMILY, QUALIFIER, VALUE);
2075        table.put(put);
2076      }
2077
2078      // scan forward
2079      try (ResultScanner scanner = table.getScanner(new Scan())) {
2080        int count = 0;
2081        for (Result r : scanner) {
2082          assertTrue(!r.isEmpty());
2083          count++;
2084        }
2085        assertEquals(12, count);
2086      }
2087
2088      reverseScanTest(table, false);
2089      reverseScanTest(table, true);
2090    }
2091  }
2092
2093  private void reverseScanTest(Table table, boolean small) throws IOException {
2094    // scan backward
2095    Scan scan = new Scan();
2096    scan.setReversed(true);
2097    try (ResultScanner scanner = table.getScanner(scan)) {
2098      int count = 0;
2099      byte[] lastRow = null;
2100      for (Result r : scanner) {
2101        assertTrue(!r.isEmpty());
2102        count++;
2103        byte[] thisRow = r.getRow();
2104        if (lastRow != null) {
2105          assertTrue("Error scan order, last row= " + Bytes.toString(lastRow)
2106                          + ",this row=" + Bytes.toString(thisRow),
2107                  Bytes.compareTo(thisRow, lastRow) < 0);
2108        }
2109        lastRow = thisRow;
2110      }
2111      assertEquals(12, count);
2112    }
2113
2114    scan = new Scan();
2115    scan.setSmall(small);
2116    scan.setReversed(true);
2117    scan.setStartRow(Bytes.toBytes("002"));
2118    try (ResultScanner scanner = table.getScanner(scan)) {
2119      int count = 0;
2120      byte[] lastRow = null;
2121      for (Result r : scanner) {
2122        assertTrue(!r.isEmpty());
2123        count++;
2124        byte[] thisRow = r.getRow();
2125        if (lastRow != null) {
2126          assertTrue("Error scan order, last row= " + Bytes.toString(lastRow)
2127                          + ",this row=" + Bytes.toString(thisRow),
2128                  Bytes.compareTo(thisRow, lastRow) < 0);
2129        }
2130        lastRow = thisRow;
2131      }
2132      assertEquals(3, count); // 000 001 002
2133    }
2134
2135    scan = new Scan();
2136    scan.setSmall(small);
2137    scan.setReversed(true);
2138    scan.setStartRow(Bytes.toBytes("002"));
2139    scan.setStopRow(Bytes.toBytes("000"));
2140    try (ResultScanner scanner = table.getScanner(scan)) {
2141      int count = 0;
2142      byte[] lastRow = null;
2143      for (Result r : scanner) {
2144        assertFalse(r.isEmpty());
2145        count++;
2146        byte[] thisRow = r.getRow();
2147        if (lastRow != null) {
2148          assertTrue("Error scan order, last row= " + Bytes.toString(lastRow)
2149                          + ",this row=" + Bytes.toString(thisRow),
2150                  Bytes.compareTo(thisRow, lastRow) < 0);
2151        }
2152        lastRow = thisRow;
2153      }
2154      assertEquals(2, count); // 001 002
2155    }
2156
2157    scan = new Scan();
2158    scan.setSmall(small);
2159    scan.setReversed(true);
2160    scan.setStartRow(Bytes.toBytes("001"));
2161    try (ResultScanner scanner = table.getScanner(scan)) {
2162      int count = 0;
2163      byte[] lastRow = null;
2164      for (Result r : scanner) {
2165        assertFalse(r.isEmpty());
2166        count++;
2167        byte[] thisRow = r.getRow();
2168        if (lastRow != null) {
2169          assertTrue("Error scan order, last row= " + Bytes.toString(lastRow)
2170                          + ",this row=" + Bytes.toString(thisRow),
2171                  Bytes.compareTo(thisRow, lastRow) < 0);
2172        }
2173        lastRow = thisRow;
2174      }
2175      assertEquals(2, count); // 000 001
2176    }
2177
2178    scan = new Scan();
2179    scan.setSmall(small);
2180    scan.setReversed(true);
2181    scan.setStartRow(Bytes.toBytes("000"));
2182    try (ResultScanner scanner = table.getScanner(scan)) {
2183      int count = 0;
2184      byte[] lastRow = null;
2185      for (Result r : scanner) {
2186        assertFalse(r.isEmpty());
2187        count++;
2188        byte[] thisRow = r.getRow();
2189        if (lastRow != null) {
2190          assertTrue("Error scan order, last row= " + Bytes.toString(lastRow)
2191                          + ",this row=" + Bytes.toString(thisRow),
2192                  Bytes.compareTo(thisRow, lastRow) < 0);
2193        }
2194        lastRow = thisRow;
2195      }
2196      assertEquals(1, count); // 000
2197    }
2198
2199    scan = new Scan();
2200    scan.setSmall(small);
2201    scan.setReversed(true);
2202    scan.setStartRow(Bytes.toBytes("006"));
2203    scan.setStopRow(Bytes.toBytes("002"));
2204    try (ResultScanner scanner = table.getScanner(scan)) {
2205      int count = 0;
2206      byte[] lastRow = null;
2207      for (Result r : scanner) {
2208        assertFalse(r.isEmpty());
2209        count++;
2210        byte[] thisRow = r.getRow();
2211        if (lastRow != null) {
2212          assertTrue("Error scan order, last row= " + Bytes.toString(lastRow)
2213                          + ",this row=" + Bytes.toString(thisRow),
2214                  Bytes.compareTo(thisRow, lastRow) < 0);
2215        }
2216        lastRow = thisRow;
2217      }
2218      assertEquals(4, count); // 003 004 005 006
2219    }
2220  }
2221
2222  @Test
2223  public void testFilterAllRecords() throws IOException {
2224    Scan scan = new Scan();
2225    scan.setBatch(1);
2226    scan.setCaching(1);
2227    // Filter out any records
2228    scan.setFilter(new FilterList(new FirstKeyOnlyFilter(), new InclusiveStopFilter(new byte[0])));
2229    try (Table table = TEST_UTIL.getConnection().getTable(TableName.META_TABLE_NAME)) {
2230      try (ResultScanner s = table.getScanner(scan)) {
2231        assertNull(s.next());
2232      }
2233    }
2234  }
2235
2236  @Test
2237  public void testCellSizeLimit() throws IOException {
2238    final TableName tableName = name.getTableName();
2239    TableDescriptorBuilder.ModifyableTableDescriptor tableDescriptor =
2240      new TableDescriptorBuilder.ModifyableTableDescriptor(tableName)
2241        .setValue(HRegion.HBASE_MAX_CELL_SIZE_KEY, Integer.toString(10 * 1024));
2242    ColumnFamilyDescriptor familyDescriptor =
2243      new ColumnFamilyDescriptorBuilder.ModifyableColumnFamilyDescriptor(FAMILY);
2244
2245    tableDescriptor.setColumnFamily(familyDescriptor);
2246    try (Admin admin = TEST_UTIL.getAdmin()) {
2247      admin.createTable(tableDescriptor);
2248    }
2249    // Will succeed
2250    try (Table t = TEST_UTIL.getConnection().getTable(tableName)) {
2251      t.put(new Put(ROW).addColumn(FAMILY, QUALIFIER, Bytes.toBytes(0L)));
2252      t.increment(new Increment(ROW).addColumn(FAMILY, QUALIFIER, 1L));
2253    }
2254    // Will succeed
2255    try (Table t = TEST_UTIL.getConnection().getTable(tableName)) {
2256      t.put(new Put(ROW).addColumn(FAMILY, QUALIFIER, new byte[9*1024]));
2257    }
2258    // Will fail
2259    try (Table t = TEST_UTIL.getConnection().getTable(tableName)) {
2260      try {
2261        t.put(new Put(ROW).addColumn(FAMILY, QUALIFIER, new byte[10 * 1024]));
2262        fail("Oversize cell failed to trigger exception");
2263      } catch (IOException e) {
2264        // expected
2265      }
2266      try {
2267        t.append(new Append(ROW).addColumn(FAMILY, QUALIFIER, new byte[2 * 1024]));
2268        fail("Oversize cell failed to trigger exception");
2269      } catch (IOException e) {
2270        // expected
2271      }
2272    }
2273  }
2274
2275  @Test
2276  public void testCellSizeNoLimit() throws IOException {
2277    final TableName tableName = name.getTableName();
2278    ColumnFamilyDescriptor familyDescriptor =
2279      new ColumnFamilyDescriptorBuilder.ModifyableColumnFamilyDescriptor(FAMILY);
2280    TableDescriptorBuilder.ModifyableTableDescriptor tableDescriptor =
2281      new TableDescriptorBuilder.ModifyableTableDescriptor(tableName)
2282        .setValue(HRegion.HBASE_MAX_CELL_SIZE_KEY, Integer.toString(0));
2283    tableDescriptor.setColumnFamily(familyDescriptor);
2284
2285    try (Admin admin = TEST_UTIL.getAdmin()) {
2286      admin.createTable(tableDescriptor);
2287    }
2288
2289    // Will succeed
2290    try (Table ht = TEST_UTIL.getConnection().getTable(tableName)) {
2291      ht.put(new Put(ROW).addColumn(FAMILY, QUALIFIER,  new byte[HRegion.DEFAULT_MAX_CELL_SIZE -
2292        1024]));
2293      ht.append(new Append(ROW).addColumn(FAMILY, QUALIFIER, new byte[1024 + 1]));
2294    }
2295  }
2296
2297  @Test
2298  public void testDeleteSpecifiedVersionOfSpecifiedColumn() throws Exception {
2299    final TableName tableName = name.getTableName();
2300
2301    byte[][] VALUES = makeN(VALUE, 5);
2302    long[] ts = {1000, 2000, 3000, 4000, 5000};
2303
2304    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 5)) {
2305
2306      Put put = new Put(ROW);
2307      // Put version 1000,2000,3000,4000 of column FAMILY:QUALIFIER
2308      for (int t = 0; t < 4; t++) {
2309        put.addColumn(FAMILY, QUALIFIER, ts[t], VALUES[t]);
2310      }
2311      ht.put(put);
2312
2313      Delete delete = new Delete(ROW);
2314      // Delete version 3000 of column FAMILY:QUALIFIER
2315      delete.addColumn(FAMILY, QUALIFIER, ts[2]);
2316      ht.delete(delete);
2317
2318      Get get = new Get(ROW);
2319      get.addColumn(FAMILY, QUALIFIER);
2320      get.readVersions(Integer.MAX_VALUE);
2321      Result result = ht.get(get);
2322      // verify version 1000,2000,4000 remains for column FAMILY:QUALIFIER
2323      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0], ts[1], ts[3]}, new byte[][]{
2324              VALUES[0], VALUES[1], VALUES[3]}, 0, 2);
2325
2326      delete = new Delete(ROW);
2327      // Delete a version 5000 of column FAMILY:QUALIFIER which didn't exist
2328      delete.addColumn(FAMILY, QUALIFIER, ts[4]);
2329      ht.delete(delete);
2330
2331      get = new Get(ROW);
2332      get.addColumn(FAMILY, QUALIFIER);
2333      get.readVersions(Integer.MAX_VALUE);
2334      result = ht.get(get);
2335      // verify version 1000,2000,4000 remains for column FAMILY:QUALIFIER
2336      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0], ts[1], ts[3]}, new byte[][]{
2337              VALUES[0], VALUES[1], VALUES[3]}, 0, 2);
2338    }
2339  }
2340
2341  @Test
2342  public void testDeleteLatestVersionOfSpecifiedColumn() throws Exception {
2343    final TableName tableName = name.getTableName();
2344    byte[][] VALUES = makeN(VALUE, 5);
2345    long[] ts = {1000, 2000, 3000, 4000, 5000};
2346    try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 5)) {
2347      Put put = new Put(ROW);
2348      // Put version 1000,2000,3000,4000 of column FAMILY:QUALIFIER
2349      for (int t = 0; t < 4; t++) {
2350        put.addColumn(FAMILY, QUALIFIER, ts[t], VALUES[t]);
2351      }
2352      ht.put(put);
2353
2354      Delete delete = new Delete(ROW);
2355      // Delete latest version of column FAMILY:QUALIFIER
2356      delete.addColumn(FAMILY, QUALIFIER);
2357      ht.delete(delete);
2358
2359      Get get = new Get(ROW);
2360      get.addColumn(FAMILY, QUALIFIER);
2361      get.readVersions(Integer.MAX_VALUE);
2362      Result result = ht.get(get);
2363      // verify version 1000,2000,3000 remains for column FAMILY:QUALIFIER
2364      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0], ts[1], ts[2]}, new byte[][]{
2365              VALUES[0], VALUES[1], VALUES[2]}, 0, 2);
2366
2367      delete = new Delete(ROW);
2368      // Delete two latest version of column FAMILY:QUALIFIER
2369      delete.addColumn(FAMILY, QUALIFIER);
2370      delete.addColumn(FAMILY, QUALIFIER);
2371      ht.delete(delete);
2372
2373      get = new Get(ROW);
2374      get.addColumn(FAMILY, QUALIFIER);
2375      get.readVersions(Integer.MAX_VALUE);
2376      result = ht.get(get);
2377      // verify version 1000 remains for column FAMILY:QUALIFIER
2378      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0]}, new byte[][]{VALUES[0]},
2379              0, 0);
2380
2381      put = new Put(ROW);
2382      // Put a version 5000 of column FAMILY:QUALIFIER
2383      put.addColumn(FAMILY, QUALIFIER, ts[4], VALUES[4]);
2384      ht.put(put);
2385
2386      get = new Get(ROW);
2387      get.addColumn(FAMILY, QUALIFIER);
2388      get.readVersions(Integer.MAX_VALUE);
2389      result = ht.get(get);
2390      // verify version 1000,5000 remains for column FAMILY:QUALIFIER
2391      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0], ts[4]}, new byte[][]{
2392              VALUES[0], VALUES[4]}, 0, 1);
2393    }
2394  }
2395
2396  /**
2397   * Test for HBASE-17125
2398   */
2399  @Test
2400  public void testReadWithFilter() throws Exception {
2401    final TableName tableName = name.getTableName();
2402    try (Table table = TEST_UTIL.createTable(tableName, FAMILY, 3)) {
2403
2404      byte[] VALUEA = Bytes.toBytes("value-a");
2405      byte[] VALUEB = Bytes.toBytes("value-b");
2406      long[] ts = {1000, 2000, 3000, 4000};
2407
2408      Put put = new Put(ROW);
2409      // Put version 1000,2000,3000,4000 of column FAMILY:QUALIFIER
2410      for (int t = 0; t <= 3; t++) {
2411        if (t <= 1) {
2412          put.addColumn(FAMILY, QUALIFIER, ts[t], VALUEA);
2413        } else {
2414          put.addColumn(FAMILY, QUALIFIER, ts[t], VALUEB);
2415        }
2416      }
2417      table.put(put);
2418
2419      Scan scan =
2420              new Scan().setFilter(new ValueFilter(CompareOperator.EQUAL,
2421                      new SubstringComparator("value-a")))
2422                      .setMaxVersions(3);
2423      ResultScanner scanner = table.getScanner(scan);
2424      Result result = scanner.next();
2425      // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3
2426      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0,
2427              0);
2428
2429      Get get =
2430              new Get(ROW)
2431                      .setFilter(new ValueFilter(CompareOperator.EQUAL,
2432                              new SubstringComparator("value-a")))
2433                      .readVersions(3);
2434      result = table.get(get);
2435      // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3
2436      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0,
2437              0);
2438
2439      // Test with max versions 1, it should still read ts[1]
2440      scan =
2441              new Scan().setFilter(new ValueFilter(CompareOperator.EQUAL,
2442                      new SubstringComparator("value-a")))
2443                      .setMaxVersions(1);
2444      scanner = table.getScanner(scan);
2445      result = scanner.next();
2446      // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3
2447      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0,
2448              0);
2449
2450      // Test with max versions 1, it should still read ts[1]
2451      get =
2452              new Get(ROW)
2453                      .setFilter(new ValueFilter(CompareOperator.EQUAL,
2454                              new SubstringComparator("value-a")))
2455                      .readVersions(1);
2456      result = table.get(get);
2457      // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3
2458      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0,
2459              0);
2460
2461      // Test with max versions 5, it should still read ts[1]
2462      scan =
2463              new Scan().setFilter(new ValueFilter(CompareOperator.EQUAL,
2464                      new SubstringComparator("value-a")))
2465                      .setMaxVersions(5);
2466      scanner = table.getScanner(scan);
2467      result = scanner.next();
2468      // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3
2469      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0,
2470              0);
2471
2472      // Test with max versions 5, it should still read ts[1]
2473      get =
2474              new Get(ROW)
2475                      .setFilter(new ValueFilter(CompareOperator.EQUAL,
2476                              new SubstringComparator("value-a")))
2477                      .readVersions(5);
2478      result = table.get(get);
2479      // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3
2480      assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0,
2481              0);
2482    }
2483  }
2484
2485  @Test
2486  public void testCellUtilTypeMethods() throws IOException {
2487    final TableName tableName = name.getTableName();
2488    try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) {
2489
2490      final byte[] row = Bytes.toBytes("p");
2491      Put p = new Put(row);
2492      p.addColumn(FAMILY, QUALIFIER, VALUE);
2493      table.put(p);
2494
2495      try (ResultScanner scanner = table.getScanner(new Scan())) {
2496        Result result = scanner.next();
2497        assertNotNull(result);
2498        CellScanner cs = result.cellScanner();
2499        assertTrue(cs.advance());
2500        Cell c = cs.current();
2501        assertTrue(CellUtil.isPut(c));
2502        assertFalse(CellUtil.isDelete(c));
2503        assertFalse(cs.advance());
2504        assertNull(scanner.next());
2505      }
2506
2507      Delete d = new Delete(row);
2508      d.addColumn(FAMILY, QUALIFIER);
2509      table.delete(d);
2510
2511      Scan scan = new Scan();
2512      scan.setRaw(true);
2513      try (ResultScanner scanner = table.getScanner(scan)) {
2514        Result result = scanner.next();
2515        assertNotNull(result);
2516        CellScanner cs = result.cellScanner();
2517        assertTrue(cs.advance());
2518
2519        // First cell should be the delete (masking the Put)
2520        Cell c = cs.current();
2521        assertTrue("Cell should be a Delete: " + c, CellUtil.isDelete(c));
2522        assertFalse("Cell should not be a Put: " + c, CellUtil.isPut(c));
2523
2524        // Second cell should be the original Put
2525        assertTrue(cs.advance());
2526        c = cs.current();
2527        assertFalse("Cell should not be a Delete: " + c, CellUtil.isDelete(c));
2528        assertTrue("Cell should be a Put: " + c, CellUtil.isPut(c));
2529
2530        // No more cells in this row
2531        assertFalse(cs.advance());
2532
2533        // No more results in this scan
2534        assertNull(scanner.next());
2535      }
2536    }
2537  }
2538
2539  @Test(expected = DoNotRetryIOException.class)
2540  public void testCreateTableWithZeroRegionReplicas() throws Exception {
2541    TableName tableName = name.getTableName();
2542    TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
2543        .setColumnFamily(ColumnFamilyDescriptorBuilder.of(Bytes.toBytes("cf")))
2544        .setRegionReplication(0)
2545        .build();
2546
2547    TEST_UTIL.getAdmin().createTable(desc);
2548  }
2549
2550  @Test(expected = DoNotRetryIOException.class)
2551  public void testModifyTableWithZeroRegionReplicas() throws Exception {
2552    TableName tableName = name.getTableName();
2553    TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
2554        .setColumnFamily(ColumnFamilyDescriptorBuilder.of(Bytes.toBytes("cf")))
2555        .build();
2556
2557    TEST_UTIL.getAdmin().createTable(desc);
2558    TableDescriptor newDesc = TableDescriptorBuilder.newBuilder(desc)
2559        .setRegionReplication(0)
2560        .build();
2561
2562    TEST_UTIL.getAdmin().modifyTable(newDesc);
2563  }
2564
2565  @Test(timeout = 60000)
2566  public void testModifyTableWithMemstoreData() throws Exception {
2567    TableName tableName = name.getTableName();
2568    createTableAndValidateTableSchemaModification(tableName, true);
2569  }
2570
2571  @Test(timeout = 60000)
2572  public void testDeleteCFWithMemstoreData() throws Exception {
2573    TableName tableName = name.getTableName();
2574    createTableAndValidateTableSchemaModification(tableName, false);
2575  }
2576
2577  /**
2578   * Create table and validate online schema modification
2579   * @param tableName Table name
2580   * @param modifyTable Modify table if true otherwise delete column family
2581   * @throws IOException in case of failures
2582   */
2583  private void createTableAndValidateTableSchemaModification(TableName tableName,
2584      boolean modifyTable) throws Exception {
2585    Admin admin = TEST_UTIL.getAdmin();
2586    // Create table with two Cfs
2587    byte[] cf1 = Bytes.toBytes("cf1");
2588    byte[] cf2 = Bytes.toBytes("cf2");
2589    TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(tableName)
2590        .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf1))
2591        .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf2)).build();
2592    admin.createTable(tableDesc);
2593
2594    Table t = TEST_UTIL.getConnection().getTable(tableName);
2595    // Insert few records and flush the table
2596    t.put(new Put(ROW).addColumn(cf1, QUALIFIER, Bytes.toBytes("val1")));
2597    t.put(new Put(ROW).addColumn(cf2, QUALIFIER, Bytes.toBytes("val2")));
2598    admin.flush(tableName);
2599    Path tableDir = CommonFSUtils.getTableDir(TEST_UTIL.getDefaultRootDirPath(), tableName);
2600    List<Path> regionDirs = FSUtils.getRegionDirs(TEST_UTIL.getTestFileSystem(), tableDir);
2601    assertEquals(1, regionDirs.size());
2602    List<Path> familyDirs = FSUtils.getFamilyDirs(TEST_UTIL.getTestFileSystem(), regionDirs.get(0));
2603    assertEquals(2, familyDirs.size());
2604
2605    // Insert record but dont flush the table
2606    t.put(new Put(ROW).addColumn(cf1, QUALIFIER, Bytes.toBytes("val2")));
2607    t.put(new Put(ROW).addColumn(cf2, QUALIFIER, Bytes.toBytes("val2")));
2608
2609    if (modifyTable) {
2610      tableDesc = TableDescriptorBuilder.newBuilder(tableDesc).removeColumnFamily(cf2).build();
2611      admin.modifyTable(tableDesc);
2612    } else {
2613      admin.deleteColumnFamily(tableName, cf2);
2614    }
2615    // After table modification or delete family there should be only one CF in FS
2616    familyDirs = FSUtils.getFamilyDirs(TEST_UTIL.getTestFileSystem(), regionDirs.get(0));
2617    assertEquals("CF dir count should be 1, but was " + familyDirs.size(), 1, familyDirs.size());
2618  }
2619}