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.regionserver.storefiletracker; 019 020import static org.junit.Assert.assertArrayEquals; 021import static org.junit.Assert.assertEquals; 022import static org.junit.Assert.assertThrows; 023 024import java.io.IOException; 025import org.apache.hadoop.hbase.DoNotRetryIOException; 026import org.apache.hadoop.hbase.HBaseClassTestRule; 027import org.apache.hadoop.hbase.HBaseTestingUtility; 028import org.apache.hadoop.hbase.TableName; 029import org.apache.hadoop.hbase.TableNameTestRule; 030import org.apache.hadoop.hbase.TableNotEnabledException; 031import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 032import org.apache.hadoop.hbase.client.Get; 033import org.apache.hadoop.hbase.client.Put; 034import org.apache.hadoop.hbase.client.Table; 035import org.apache.hadoop.hbase.client.TableDescriptor; 036import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 037import org.apache.hadoop.hbase.testclassification.MediumTests; 038import org.apache.hadoop.hbase.testclassification.RegionServerTests; 039import org.apache.hadoop.hbase.util.Bytes; 040import org.junit.AfterClass; 041import org.junit.BeforeClass; 042import org.junit.ClassRule; 043import org.junit.Rule; 044import org.junit.Test; 045import org.junit.experimental.categories.Category; 046 047import org.apache.hbase.thirdparty.com.google.common.collect.Iterables; 048 049/** 050 * Test changing store file tracker implementation by altering table. 051 */ 052@Category({ RegionServerTests.class, MediumTests.class }) 053public class TestChangeStoreFileTracker { 054 055 @ClassRule 056 public static final HBaseClassTestRule CLASS_RULE = 057 HBaseClassTestRule.forClass(TestChangeStoreFileTracker.class); 058 059 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); 060 061 @Rule 062 public final TableNameTestRule tableName = new TableNameTestRule(); 063 064 @BeforeClass 065 public static void setUp() throws Exception { 066 UTIL.startMiniCluster(1); 067 } 068 069 @AfterClass 070 public static void tearDown() throws IOException { 071 UTIL.shutdownMiniCluster(); 072 } 073 074 @Test(expected = DoNotRetryIOException.class) 075 public void testCreateError() throws IOException { 076 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName.getTableName()) 077 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("family")) 078 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, 079 StoreFileTrackerFactory.Trackers.MIGRATION.name()) 080 .setValue(MigrationStoreFileTracker.SRC_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 081 .setValue(MigrationStoreFileTracker.DST_IMPL, StoreFileTrackerFactory.Trackers.FILE.name()) 082 .build(); 083 UTIL.getAdmin().createTable(td); 084 } 085 086 @Test(expected = DoNotRetryIOException.class) 087 public void testModifyError1() throws IOException { 088 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName.getTableName()) 089 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("family")).build(); 090 UTIL.getAdmin().createTable(td); 091 TableDescriptor newTd = TableDescriptorBuilder.newBuilder(td) 092 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, StoreFileTrackerFactory.Trackers.FILE.name()) 093 .build(); 094 UTIL.getAdmin().modifyTable(newTd); 095 } 096 097 @Test(expected = DoNotRetryIOException.class) 098 public void testModifyError2() throws IOException { 099 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName.getTableName()) 100 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("family")).build(); 101 UTIL.getAdmin().createTable(td); 102 TableDescriptor newTd = TableDescriptorBuilder.newBuilder(td) 103 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, 104 StoreFileTrackerFactory.Trackers.MIGRATION.name()) 105 .setValue(MigrationStoreFileTracker.SRC_IMPL, StoreFileTrackerFactory.Trackers.FILE.name()) 106 .setValue(MigrationStoreFileTracker.DST_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 107 .build(); 108 UTIL.getAdmin().modifyTable(newTd); 109 } 110 111 @Test(expected = DoNotRetryIOException.class) 112 public void testModifyError3() throws IOException { 113 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName.getTableName()) 114 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("family")).build(); 115 UTIL.getAdmin().createTable(td); 116 TableDescriptor newTd = TableDescriptorBuilder.newBuilder(td) 117 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, 118 StoreFileTrackerFactory.Trackers.MIGRATION.name()) 119 .setValue(MigrationStoreFileTracker.SRC_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 120 .setValue(MigrationStoreFileTracker.DST_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 121 .build(); 122 UTIL.getAdmin().modifyTable(newTd); 123 } 124 125 // return the TableDescriptor for creating table 126 private TableDescriptor createTableAndChangeToMigrationTracker() throws IOException { 127 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName.getTableName()) 128 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("family")).build(); 129 UTIL.getAdmin().createTable(td); 130 TableDescriptor newTd = TableDescriptorBuilder.newBuilder(td) 131 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, 132 StoreFileTrackerFactory.Trackers.MIGRATION.name()) 133 .setValue(MigrationStoreFileTracker.SRC_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 134 .setValue(MigrationStoreFileTracker.DST_IMPL, StoreFileTrackerFactory.Trackers.FILE.name()) 135 .build(); 136 UTIL.getAdmin().modifyTable(newTd); 137 return td; 138 } 139 140 @Test(expected = DoNotRetryIOException.class) 141 public void testModifyError4() throws IOException { 142 TableDescriptor td = createTableAndChangeToMigrationTracker(); 143 TableDescriptor newTd = TableDescriptorBuilder.newBuilder(td) 144 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, 145 StoreFileTrackerFactory.Trackers.MIGRATION.name()) 146 .setValue(MigrationStoreFileTracker.SRC_IMPL, StoreFileTrackerFactory.Trackers.FILE.name()) 147 .setValue(MigrationStoreFileTracker.DST_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 148 .build(); 149 UTIL.getAdmin().modifyTable(newTd); 150 } 151 152 @Test(expected = DoNotRetryIOException.class) 153 public void testModifyError5() throws IOException { 154 TableDescriptor td = createTableAndChangeToMigrationTracker(); 155 TableDescriptor newTd = TableDescriptorBuilder.newBuilder(td) 156 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, 157 StoreFileTrackerFactory.Trackers.MIGRATION.name()) 158 .setValue(MigrationStoreFileTracker.SRC_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 159 .setValue(MigrationStoreFileTracker.DST_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 160 .build(); 161 UTIL.getAdmin().modifyTable(newTd); 162 } 163 164 @Test(expected = DoNotRetryIOException.class) 165 public void testModifyError6() throws IOException { 166 TableDescriptor td = createTableAndChangeToMigrationTracker(); 167 TableDescriptor newTd = 168 TableDescriptorBuilder.newBuilder(td).setValue(StoreFileTrackerFactory.TRACKER_IMPL, 169 StoreFileTrackerFactory.Trackers.DEFAULT.name()).build(); 170 UTIL.getAdmin().modifyTable(newTd); 171 } 172 173 @Test(expected = DoNotRetryIOException.class) 174 public void testModifyError7() throws IOException { 175 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName.getTableName()) 176 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("family")).build(); 177 UTIL.getAdmin().createTable(td); 178 TableDescriptor newTd = TableDescriptorBuilder.newBuilder(tableName.getTableName()) 179 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("family")) 180 .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("family1")) 181 .setConfiguration(StoreFileTrackerFactory.TRACKER_IMPL, 182 StoreFileTrackerFactory.Trackers.MIGRATION.name()) 183 .build()) 184 .build(); 185 UTIL.getAdmin().modifyTable(newTd); 186 } 187 188 // actually a NPE as we do not specify the src and dst impl for migration store file tracker 189 @Test(expected = IOException.class) 190 public void testModifyError8() throws IOException { 191 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName.getTableName()) 192 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("family")).build(); 193 UTIL.getAdmin().createTable(td); 194 TableDescriptor newTd = 195 TableDescriptorBuilder.newBuilder(td).setValue(StoreFileTrackerFactory.TRACKER_IMPL, 196 StoreFileTrackerFactory.Trackers.MIGRATION.name()).build(); 197 UTIL.getAdmin().modifyTable(newTd); 198 } 199 200 @Test 201 public void testModifyError9() throws IOException { 202 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName.getTableName()) 203 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("family")).build(); 204 UTIL.getAdmin().createTable(td); 205 UTIL.getAdmin().disableTable(td.getTableName()); 206 TableDescriptor newTd = TableDescriptorBuilder.newBuilder(td) 207 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, 208 StoreFileTrackerFactory.Trackers.MIGRATION.name()) 209 .setValue(MigrationStoreFileTracker.SRC_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 210 .setValue(MigrationStoreFileTracker.DST_IMPL, StoreFileTrackerFactory.Trackers.FILE.name()) 211 .build(); 212 UTIL.getAdmin().modifyTable(newTd); 213 TableDescriptor newTd2 = TableDescriptorBuilder.newBuilder(td) 214 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, StoreFileTrackerFactory.Trackers.FILE.name()) 215 .build(); 216 // changing from MIGRATION while table is disabled is not allowed 217 assertThrows(TableNotEnabledException.class, () -> UTIL.getAdmin().modifyTable(newTd2)); 218 } 219 220 private String getStoreFileName(TableName table, byte[] family) { 221 return Iterables 222 .getOnlyElement(Iterables.getOnlyElement(UTIL.getMiniHBaseCluster().getRegions(table)) 223 .getStore(family).getStorefiles()) 224 .getPath().getName(); 225 } 226 227 @Test 228 public void testModify() throws IOException { 229 TableName tn = tableName.getTableName(); 230 byte[] row = Bytes.toBytes("row"); 231 byte[] family = Bytes.toBytes("family"); 232 byte[] qualifier = Bytes.toBytes("qualifier"); 233 byte[] value = Bytes.toBytes("value"); 234 TableDescriptor td = TableDescriptorBuilder.newBuilder(tn) 235 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)).build(); 236 UTIL.getAdmin().createTable(td); 237 try (Table table = UTIL.getConnection().getTable(tn)) { 238 table.put(new Put(row).addColumn(family, qualifier, value)); 239 } 240 UTIL.flush(tn); 241 String fileName = getStoreFileName(tn, family); 242 243 TableDescriptor newTd = TableDescriptorBuilder.newBuilder(td) 244 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, 245 StoreFileTrackerFactory.Trackers.MIGRATION.name()) 246 .setValue(MigrationStoreFileTracker.SRC_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()) 247 .setValue(MigrationStoreFileTracker.DST_IMPL, StoreFileTrackerFactory.Trackers.FILE.name()) 248 .build(); 249 UTIL.getAdmin().modifyTable(newTd); 250 assertEquals(fileName, getStoreFileName(tn, family)); 251 try (Table table = UTIL.getConnection().getTable(tn)) { 252 assertArrayEquals(value, table.get(new Get(row)).getValue(family, qualifier)); 253 } 254 255 TableDescriptor newTd2 = TableDescriptorBuilder.newBuilder(td) 256 .setValue(StoreFileTrackerFactory.TRACKER_IMPL, StoreFileTrackerFactory.Trackers.FILE.name()) 257 .build(); 258 UTIL.getAdmin().modifyTable(newTd2); 259 assertEquals(fileName, getStoreFileName(tn, family)); 260 try (Table table = UTIL.getConnection().getTable(tn)) { 261 assertArrayEquals(value, table.get(new Get(row)).getValue(family, qualifier)); 262 } 263 } 264}