Skip to content

Commit a4b192e

Browse files
committed
HBASE-26611 Changing SFT implementation on disabled table is dangerous (#4082)
Signed-off-by: Xiaolin Ha <[email protected]>
1 parent 350db51 commit a4b192e

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ private void prepareModify(final MasterProcedureEnv env) throws IOException {
321321

322322
// check for store file tracker configurations
323323
StoreFileTrackerValidationUtils.checkForModifyTable(env.getMasterConfiguration(),
324-
unmodifiedTableDescriptor, modifiedTableDescriptor);
324+
unmodifiedTableDescriptor, modifiedTableDescriptor, !isTableEnabled(env));
325325
}
326326

327327
/**

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/storefiletracker/StoreFileTrackerValidationUtils.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.io.IOException;
2121
import org.apache.hadoop.conf.Configuration;
2222
import org.apache.hadoop.hbase.DoNotRetryIOException;
23+
import org.apache.hadoop.hbase.TableNotEnabledException;
2324
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
2425
import org.apache.hadoop.hbase.client.TableDescriptor;
2526
import org.apache.hadoop.hbase.regionserver.StoreUtils;
@@ -94,7 +95,7 @@ public static void checkForCreateTable(Configuration conf, TableDescriptor table
9495
* {@code ModifyTableProcedure}.
9596
*/
9697
public static void checkForModifyTable(Configuration conf, TableDescriptor oldTable,
97-
TableDescriptor newTable) throws IOException {
98+
TableDescriptor newTable, boolean isTableDisabled) throws IOException {
9899
for (ColumnFamilyDescriptor newFamily : newTable.getColumnFamilies()) {
99100
ColumnFamilyDescriptor oldFamily = oldTable.getColumnFamily(newFamily.getName());
100101
if (oldFamily == null) {
@@ -133,6 +134,16 @@ public static void checkForModifyTable(Configuration conf, TableDescriptor oldTa
133134
newFamily.getNameAsString() + " of table " + newTable.getTableName());
134135
}
135136
} else {
137+
// do not allow changing from MIGRATION to its dst SFT implementation while the table is
138+
// disabled. We need to open the HRegion to migrate the tracking information while the SFT
139+
// implementation is MIGRATION, otherwise we may loss data. See HBASE-26611 for more
140+
// details.
141+
if (isTableDisabled) {
142+
throw new TableNotEnabledException(
143+
"Should not change store file tracker implementation from " +
144+
StoreFileTrackerFactory.Trackers.MIGRATION.name() + " while table " +
145+
newTable.getTableName() + " is disabled");
146+
}
136147
// we can only change to the dst tracker
137148
if (!newTracker.equals(oldDstTracker)) {
138149
throw new DoNotRetryIOException("Should migrate tracker to " +
@@ -151,6 +162,9 @@ public static void checkForModifyTable(Configuration conf, TableDescriptor oldTa
151162
StoreFileTrackerFactory.getStoreFileTrackerName(oldTracker) + " for family " +
152163
newFamily.getNameAsString() + " of table " + newTable.getTableName());
153164
}
165+
// here we do not check whether the table is disabled, as after changing to MIGRATION, we
166+
// still rely on the src SFT implementation to actually load the store files, so there
167+
// will be no data loss problem.
154168
Class<? extends StoreFileTracker> newSrcTracker =
155169
MigrationStoreFileTracker.getSrcTrackerClass(newConf);
156170
if (!oldTracker.equals(newSrcTracker)) {

hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/storefiletracker/TestChangeStoreFileTracker.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919

2020
import static org.junit.Assert.assertArrayEquals;
2121
import static org.junit.Assert.assertEquals;
22+
import static org.junit.Assert.assertThrows;
2223

2324
import java.io.IOException;
2425
import org.apache.hadoop.hbase.DoNotRetryIOException;
2526
import org.apache.hadoop.hbase.HBaseClassTestRule;
2627
import org.apache.hadoop.hbase.HBaseTestingUtility;
2728
import org.apache.hadoop.hbase.TableName;
2829
import org.apache.hadoop.hbase.TableNameTestRule;
30+
import org.apache.hadoop.hbase.TableNotEnabledException;
2931
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
3032
import org.apache.hadoop.hbase.client.Get;
3133
import org.apache.hadoop.hbase.client.Put;
@@ -195,6 +197,26 @@ public void testModifyError8() throws IOException {
195197
UTIL.getAdmin().modifyTable(newTd);
196198
}
197199

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+
198220
private String getStoreFileName(TableName table, byte[] family) {
199221
return Iterables
200222
.getOnlyElement(Iterables.getOnlyElement(UTIL.getMiniHBaseCluster().getRegions(table))

0 commit comments

Comments
 (0)