| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.hadoop.hbase.regionserver; |
| |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.IOException; |
| import java.nio.charset.StandardCharsets; |
| import java.util.ArrayList; |
| import java.util.List; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.Path; |
| import org.apache.hadoop.hbase.Cell; |
| import org.apache.hadoop.hbase.CellUtil; |
| import org.apache.hadoop.hbase.HBaseClassTestRule; |
| import org.apache.hadoop.hbase.HBaseTestingUtility; |
| import org.apache.hadoop.hbase.HConstants; |
| import org.apache.hadoop.hbase.HRegionInfo; |
| import org.apache.hadoop.hbase.HTableDescriptor; |
| import org.apache.hadoop.hbase.MetaTableAccessor; |
| import org.apache.hadoop.hbase.TableDescriptors; |
| import org.apache.hadoop.hbase.TableName; |
| import org.apache.hadoop.hbase.client.Delete; |
| import org.apache.hadoop.hbase.client.Durability; |
| import org.apache.hadoop.hbase.client.Put; |
| import org.apache.hadoop.hbase.client.RegionInfo; |
| import org.apache.hadoop.hbase.client.RegionInfoBuilder; |
| import org.apache.hadoop.hbase.client.Result; |
| import org.apache.hadoop.hbase.client.Scan; |
| import org.apache.hadoop.hbase.client.TableDescriptor; |
| import org.apache.hadoop.hbase.client.TableDescriptorBuilder; |
| import org.apache.hadoop.hbase.testclassification.MediumTests; |
| import org.apache.hadoop.hbase.testclassification.RegionServerTests; |
| import org.apache.hadoop.hbase.util.Bytes; |
| import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; |
| import org.apache.hadoop.hbase.util.FSTableDescriptors; |
| import org.apache.hadoop.hbase.wal.WAL; |
| import org.junit.ClassRule; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| import org.junit.rules.TestName; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * TestGet is a medley of tests of get all done up as a single test. |
| * It was originally written to test a method since removed, getClosestAtOrBefore |
| * but the test is retained because it runs some interesting exercises. |
| */ |
| @Category({RegionServerTests.class, MediumTests.class}) |
| public class TestGetClosestAtOrBefore { |
| |
| @ClassRule |
| public static final HBaseClassTestRule CLASS_RULE = |
| HBaseClassTestRule.forClass(TestGetClosestAtOrBefore.class); |
| |
| @Rule public TestName testName = new TestName(); |
| private static final Logger LOG = LoggerFactory.getLogger(TestGetClosestAtOrBefore.class); |
| |
| private static final byte[] T00 = Bytes.toBytes("000"); |
| private static final byte[] T10 = Bytes.toBytes("010"); |
| private static final byte[] T11 = Bytes.toBytes("011"); |
| private static final byte[] T12 = Bytes.toBytes("012"); |
| private static final byte[] T20 = Bytes.toBytes("020"); |
| private static final byte[] T30 = Bytes.toBytes("030"); |
| private static final byte[] T31 = Bytes.toBytes("031"); |
| private static final byte[] T35 = Bytes.toBytes("035"); |
| private static final byte[] T40 = Bytes.toBytes("040"); |
| |
| private static HBaseTestingUtility UTIL = new HBaseTestingUtility(); |
| private static Configuration conf = UTIL.getConfiguration(); |
| |
| @Test |
| public void testUsingMetaAndBinary() throws IOException { |
| Path rootdir = UTIL.getDataTestDirOnTestFS(); |
| // Up flush size else we bind up when we use default catalog flush of 16k. |
| TableDescriptors tds = new FSTableDescriptors(UTIL.getConfiguration()); |
| TableDescriptor td = tds.get(TableName.META_TABLE_NAME); |
| td = TableDescriptorBuilder.newBuilder(td).setMemStoreFlushSize(64 * 1024 * 1024).build(); |
| HRegion mr = HBaseTestingUtility.createRegionAndWAL(HRegionInfo.FIRST_META_REGIONINFO, |
| rootdir, this.conf, td); |
| try { |
| // Write rows for three tables 'A', 'B', and 'C'. |
| for (char c = 'A'; c < 'D'; c++) { |
| HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("" + c)); |
| final int last = 128; |
| final int interval = 2; |
| for (int i = 0; i <= last; i += interval) { |
| RegionInfo hri = RegionInfoBuilder.newBuilder(htd.getTableName()) |
| .setStartKey(i == 0 ? HConstants.EMPTY_BYTE_ARRAY : Bytes.toBytes((byte)i)) |
| .setEndKey(i == last ? HConstants.EMPTY_BYTE_ARRAY : |
| Bytes.toBytes((byte)i + interval)).build(); |
| Put put = |
| MetaTableAccessor.makePutFromRegionInfo(hri, EnvironmentEdgeManager.currentTime()); |
| put.setDurability(Durability.SKIP_WAL); |
| LOG.info("Put {}", put); |
| mr.put(put); |
| } |
| } |
| InternalScanner s = mr.getScanner(new Scan()); |
| try { |
| List<Cell> keys = new ArrayList<>(); |
| while (s.next(keys)) { |
| LOG.info("Scan {}", keys); |
| keys.clear(); |
| } |
| } finally { |
| s.close(); |
| } |
| findRow(mr, 'C', 44, 44); |
| findRow(mr, 'C', 45, 44); |
| findRow(mr, 'C', 46, 46); |
| findRow(mr, 'C', 43, 42); |
| mr.flush(true); |
| findRow(mr, 'C', 44, 44); |
| findRow(mr, 'C', 45, 44); |
| findRow(mr, 'C', 46, 46); |
| findRow(mr, 'C', 43, 42); |
| // Now delete 'C' and make sure I don't get entries from 'B'. |
| byte[] firstRowInC = RegionInfo.createRegionName(TableName.valueOf("" + 'C'), |
| HConstants.EMPTY_BYTE_ARRAY, HConstants.ZEROES, false); |
| Scan scan = new Scan().withStartRow(firstRowInC); |
| s = mr.getScanner(scan); |
| try { |
| List<Cell> keys = new ArrayList<>(); |
| while (s.next(keys)) { |
| LOG.info("Delete {}", keys); |
| mr.delete(new Delete(CellUtil.cloneRow(keys.get(0)))); |
| keys.clear(); |
| } |
| } finally { |
| s.close(); |
| } |
| // Assert we get null back (pass -1). |
| findRow(mr, 'C', 44, -1); |
| findRow(mr, 'C', 45, -1); |
| findRow(mr, 'C', 46, -1); |
| findRow(mr, 'C', 43, -1); |
| mr.flush(true); |
| findRow(mr, 'C', 44, -1); |
| findRow(mr, 'C', 45, -1); |
| findRow(mr, 'C', 46, -1); |
| findRow(mr, 'C', 43, -1); |
| } finally { |
| HBaseTestingUtility.closeRegionAndWAL(mr); |
| } |
| } |
| |
| /* |
| * @param mr |
| * @param table |
| * @param rowToFind |
| * @param answer Pass -1 if we're not to find anything. |
| * @return Row found. |
| * @throws IOException |
| */ |
| private byte [] findRow(final Region mr, final char table, |
| final int rowToFind, final int answer) |
| throws IOException { |
| TableName tableb = TableName.valueOf("" + table); |
| // Find the row. |
| byte [] tofindBytes = Bytes.toBytes((short)rowToFind); |
| byte [] metaKey = HRegionInfo.createRegionName( |
| tableb, tofindBytes, |
| HConstants.NINES, false); |
| LOG.info("find=" + new String(metaKey, StandardCharsets.UTF_8)); |
| Result r = UTIL.getClosestRowBefore(mr, metaKey, HConstants.CATALOG_FAMILY); |
| if (answer == -1) { |
| assertNull(r); |
| return null; |
| } |
| assertTrue(Bytes.compareTo(Bytes.toBytes((short)answer), |
| extractRowFromMetaRow(r.getRow())) == 0); |
| return r.getRow(); |
| } |
| |
| private byte [] extractRowFromMetaRow(final byte [] b) { |
| int firstDelimiter = Bytes.searchDelimiterIndex(b, 0, b.length, |
| HConstants.DELIMITER); |
| int lastDelimiter = Bytes.searchDelimiterIndexInReverse(b, 0, b.length, |
| HConstants.DELIMITER); |
| int length = lastDelimiter - firstDelimiter - 1; |
| byte [] row = new byte[length]; |
| System.arraycopy(b, firstDelimiter + 1, row, 0, length); |
| return row; |
| } |
| |
| /** |
| * Test file of multiple deletes and with deletes as final key. |
| * @see <a href="https://issues.apache.org/jira/browse/HBASE-751">HBASE-751</a> |
| */ |
| @Test |
| public void testGetClosestRowBefore3() throws IOException{ |
| HRegion region = null; |
| byte [] c0 = UTIL.COLUMNS[0]; |
| byte [] c1 = UTIL.COLUMNS[1]; |
| try { |
| TableName tn = TableName.valueOf(testName.getMethodName()); |
| HTableDescriptor htd = UTIL.createTableDescriptor(tn); |
| region = UTIL.createLocalHRegion(htd, null, null); |
| |
| Put p = new Put(T00); |
| p.addColumn(c0, c0, T00); |
| region.put(p); |
| |
| p = new Put(T10); |
| p.addColumn(c0, c0, T10); |
| region.put(p); |
| |
| p = new Put(T20); |
| p.addColumn(c0, c0, T20); |
| region.put(p); |
| |
| Result r = UTIL.getClosestRowBefore(region, T20, c0); |
| assertTrue(Bytes.equals(T20, r.getRow())); |
| |
| Delete d = new Delete(T20); |
| d.addColumn(c0, c0); |
| region.delete(d); |
| |
| r = UTIL.getClosestRowBefore(region, T20, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| |
| p = new Put(T30); |
| p.addColumn(c0, c0, T30); |
| region.put(p); |
| |
| r = UTIL.getClosestRowBefore(region, T30, c0); |
| assertTrue(Bytes.equals(T30, r.getRow())); |
| |
| d = new Delete(T30); |
| d.addColumn(c0, c0); |
| region.delete(d); |
| |
| r = UTIL.getClosestRowBefore(region, T30, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| r = UTIL.getClosestRowBefore(region, T31, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| |
| region.flush(true); |
| |
| // try finding "010" after flush |
| r = UTIL.getClosestRowBefore(region, T30, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| r = UTIL.getClosestRowBefore(region, T31, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| |
| // Put into a different column family. Should make it so I still get t10 |
| p = new Put(T20); |
| p.addColumn(c1, c1, T20); |
| region.put(p); |
| |
| r = UTIL.getClosestRowBefore(region, T30, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| r = UTIL.getClosestRowBefore(region, T31, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| |
| region.flush(true); |
| |
| r = UTIL.getClosestRowBefore(region, T30, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| r = UTIL.getClosestRowBefore(region, T31, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| |
| // Now try combo of memcache and mapfiles. Delete the t20 COLUMS[1] |
| // in memory; make sure we get back t10 again. |
| d = new Delete(T20); |
| d.addColumn(c1, c1); |
| region.delete(d); |
| r = UTIL.getClosestRowBefore(region, T30, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| |
| // Ask for a value off the end of the file. Should return t10. |
| r = UTIL.getClosestRowBefore(region, T31, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| region.flush(true); |
| r = UTIL.getClosestRowBefore(region, T31, c0); |
| assertTrue(Bytes.equals(T10, r.getRow())); |
| |
| // Ok. Let the candidate come out of hfile but have delete of |
| // the candidate be in memory. |
| p = new Put(T11); |
| p.addColumn(c0, c0, T11); |
| region.put(p); |
| d = new Delete(T10); |
| d.addColumn(c1, c1); |
| r = UTIL.getClosestRowBefore(region, T12, c0); |
| assertTrue(Bytes.equals(T11, r.getRow())); |
| } finally { |
| if (region != null) { |
| try { |
| WAL wal = region.getWAL(); |
| region.close(); |
| wal.close(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |
| |
| /** For HBASE-694 */ |
| @Test |
| public void testGetClosestRowBefore2() throws IOException{ |
| HRegion region = null; |
| byte [] c0 = UTIL.COLUMNS[0]; |
| try { |
| TableName tn = TableName.valueOf(testName.getMethodName()); |
| HTableDescriptor htd = UTIL.createTableDescriptor(tn); |
| region = UTIL.createLocalHRegion(htd, null, null); |
| |
| Put p = new Put(T10); |
| p.addColumn(c0, c0, T10); |
| region.put(p); |
| |
| p = new Put(T30); |
| p.addColumn(c0, c0, T30); |
| region.put(p); |
| |
| p = new Put(T40); |
| p.addColumn(c0, c0, T40); |
| region.put(p); |
| |
| // try finding "035" |
| Result r = UTIL.getClosestRowBefore(region, T35, c0); |
| assertTrue(Bytes.equals(T30, r.getRow())); |
| |
| region.flush(true); |
| |
| // try finding "035" |
| r = UTIL.getClosestRowBefore(region, T35, c0); |
| assertTrue(Bytes.equals(T30, r.getRow())); |
| |
| p = new Put(T20); |
| p.addColumn(c0, c0, T20); |
| region.put(p); |
| |
| // try finding "035" |
| r = UTIL.getClosestRowBefore(region, T35, c0); |
| assertTrue(Bytes.equals(T30, r.getRow())); |
| |
| region.flush(true); |
| |
| // try finding "035" |
| r = UTIL.getClosestRowBefore(region, T35, c0); |
| assertTrue(Bytes.equals(T30, r.getRow())); |
| } finally { |
| if (region != null) { |
| try { |
| WAL wal = region.getWAL(); |
| region.close(); |
| wal.close(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |
| |
| } |
| |