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