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.assertNull;
023import static org.junit.Assert.assertThrows;
024
025import java.io.IOException;
026import org.apache.hadoop.hbase.DoNotRetryIOException;
027import org.apache.hadoop.hbase.HBaseClassTestRule;
028import org.apache.hadoop.hbase.TableName;
029import org.apache.hadoop.hbase.TableNotEnabledException;
030import org.apache.hadoop.hbase.TableNotFoundException;
031import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException;
032import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory;
033import org.apache.hadoop.hbase.testclassification.ClientTests;
034import org.apache.hadoop.hbase.testclassification.LargeTests;
035import org.apache.hadoop.hbase.util.Bytes;
036import org.apache.hadoop.hbase.util.FutureUtils;
037import org.junit.ClassRule;
038import org.junit.Test;
039import org.junit.experimental.categories.Category;
040import org.junit.runner.RunWith;
041import org.junit.runners.Parameterized;
042
043@RunWith(Parameterized.class)
044@Category({ LargeTests.class, ClientTests.class })
045public class TestAsyncAdminModifyStoreFileTracker extends TestAsyncAdminBase {
046
047  @ClassRule
048  public static final HBaseClassTestRule CLASS_RULE =
049    HBaseClassTestRule.forClass(TestAsyncAdminModifyStoreFileTracker.class);
050
051  private static final String SRC_IMPL = "hbase.store.file-tracker.migration.src.impl";
052
053  private static final String DST_IMPL = "hbase.store.file-tracker.migration.dst.impl";
054
055  private void verifyModifyTableResult(TableName tableName, byte[] family, byte[] qual, byte[] row,
056    byte[] value, String sft) throws IOException {
057    TableDescriptor td = admin.getDescriptor(tableName).join();
058    assertEquals(sft, td.getValue(StoreFileTrackerFactory.TRACKER_IMPL));
059    // no migration related configs
060    assertNull(td.getValue(SRC_IMPL));
061    assertNull(td.getValue(DST_IMPL));
062    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
063      assertArrayEquals(value, table.get(new Get(row)).getValue(family, qual));
064    }
065  }
066
067  @Test
068  public void testModifyTableStoreFileTracker() throws IOException {
069    byte[] family = Bytes.toBytes("info");
070    byte[] qual = Bytes.toBytes("q");
071    byte[] row = Bytes.toBytes(0);
072    byte[] value = Bytes.toBytes(1);
073    try (Table table = TEST_UTIL.createTable(tableName, family)) {
074      table.put(new Put(row).addColumn(family, qual, value));
075    }
076    // change to FILE
077    admin.modifyTableStoreFileTracker(tableName, StoreFileTrackerFactory.Trackers.FILE.name())
078      .join();
079    verifyModifyTableResult(tableName, family, qual, row, value,
080      StoreFileTrackerFactory.Trackers.FILE.name());
081
082    // change to FILE again, should have no effect
083    admin.modifyTableStoreFileTracker(tableName, StoreFileTrackerFactory.Trackers.FILE.name())
084      .join();
085    verifyModifyTableResult(tableName, family, qual, row, value,
086      StoreFileTrackerFactory.Trackers.FILE.name());
087
088    // change to MIGRATION, and then to FILE
089    admin.modifyTable(TableDescriptorBuilder.newBuilder(admin.getDescriptor(tableName).join())
090      .setValue(StoreFileTrackerFactory.TRACKER_IMPL,
091        StoreFileTrackerFactory.Trackers.MIGRATION.name())
092      .setValue(SRC_IMPL, StoreFileTrackerFactory.Trackers.FILE.name())
093      .setValue(DST_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()).build()).join();
094    admin.modifyTableStoreFileTracker(tableName, StoreFileTrackerFactory.Trackers.FILE.name())
095      .join();
096    verifyModifyTableResult(tableName, family, qual, row, value,
097      StoreFileTrackerFactory.Trackers.FILE.name());
098
099    // change to MIGRATION, and then to DEFAULT
100    admin.modifyTable(TableDescriptorBuilder.newBuilder(admin.getDescriptor(tableName).join())
101      .setValue(StoreFileTrackerFactory.TRACKER_IMPL,
102        StoreFileTrackerFactory.Trackers.MIGRATION.name())
103      .setValue(SRC_IMPL, StoreFileTrackerFactory.Trackers.FILE.name())
104      .setValue(DST_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()).build()).join();
105    admin.modifyTableStoreFileTracker(tableName, StoreFileTrackerFactory.Trackers.DEFAULT.name())
106      .join();
107    verifyModifyTableResult(tableName, family, qual, row, value,
108      StoreFileTrackerFactory.Trackers.DEFAULT.name());
109  }
110
111  private void verifyModifyColumnFamilyResult(TableName tableName, byte[] family, byte[] qual,
112    byte[] row, byte[] value, String sft) throws IOException {
113    TableDescriptor td = admin.getDescriptor(tableName).join();
114    ColumnFamilyDescriptor cfd = td.getColumnFamily(family);
115    assertEquals(sft, cfd.getConfigurationValue(StoreFileTrackerFactory.TRACKER_IMPL));
116    // no migration related configs
117    assertNull(cfd.getConfigurationValue(SRC_IMPL));
118    assertNull(cfd.getConfigurationValue(DST_IMPL));
119    assertNull(cfd.getValue(SRC_IMPL));
120    assertNull(cfd.getValue(DST_IMPL));
121    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
122      assertArrayEquals(value, table.get(new Get(row)).getValue(family, qual));
123    }
124  }
125
126  @Test
127  public void testModifyColumnFamilyStoreFileTracker() throws IOException {
128    byte[] family = Bytes.toBytes("info");
129    byte[] qual = Bytes.toBytes("q");
130    byte[] row = Bytes.toBytes(0);
131    byte[] value = Bytes.toBytes(1);
132    try (Table table = TEST_UTIL.createTable(tableName, family)) {
133      table.put(new Put(row).addColumn(family, qual, value));
134    }
135    // change to FILE
136    admin.modifyColumnFamilyStoreFileTracker(tableName, family,
137      StoreFileTrackerFactory.Trackers.FILE.name()).join();
138    verifyModifyColumnFamilyResult(tableName, family, qual, row, value,
139      StoreFileTrackerFactory.Trackers.FILE.name());
140
141    // change to FILE again, should have no effect
142    admin.modifyColumnFamilyStoreFileTracker(tableName, family,
143      StoreFileTrackerFactory.Trackers.FILE.name()).join();
144    verifyModifyColumnFamilyResult(tableName, family, qual, row, value,
145      StoreFileTrackerFactory.Trackers.FILE.name());
146
147    // change to MIGRATION, and then to FILE
148    TableDescriptor current = admin.getDescriptor(tableName).join();
149    admin.modifyTable(TableDescriptorBuilder.newBuilder(current)
150      .modifyColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(current.getColumnFamily(family))
151        .setConfiguration(StoreFileTrackerFactory.TRACKER_IMPL,
152          StoreFileTrackerFactory.Trackers.MIGRATION.name())
153        .setConfiguration(SRC_IMPL, StoreFileTrackerFactory.Trackers.FILE.name())
154        .setConfiguration(DST_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()).build())
155      .build()).join();
156    admin.modifyColumnFamilyStoreFileTracker(tableName, family,
157      StoreFileTrackerFactory.Trackers.FILE.name()).join();
158    verifyModifyColumnFamilyResult(tableName, family, qual, row, value,
159      StoreFileTrackerFactory.Trackers.FILE.name());
160
161    // change to MIGRATION, and then to DEFAULT
162    current = admin.getDescriptor(tableName).join();
163    admin.modifyTable(TableDescriptorBuilder.newBuilder(current)
164      .modifyColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(current.getColumnFamily(family))
165        .setConfiguration(StoreFileTrackerFactory.TRACKER_IMPL,
166          StoreFileTrackerFactory.Trackers.MIGRATION.name())
167        .setConfiguration(SRC_IMPL, StoreFileTrackerFactory.Trackers.FILE.name())
168        .setConfiguration(DST_IMPL, StoreFileTrackerFactory.Trackers.DEFAULT.name()).build())
169      .build()).join();
170    admin.modifyColumnFamilyStoreFileTracker(tableName, family,
171      StoreFileTrackerFactory.Trackers.DEFAULT.name()).join();
172    verifyModifyColumnFamilyResult(tableName, family, qual, row, value,
173      StoreFileTrackerFactory.Trackers.DEFAULT.name());
174  }
175
176  @Test
177  public void testModifyStoreFileTrackerError() throws IOException {
178    byte[] family = Bytes.toBytes("info");
179    TEST_UTIL.createTable(tableName, family).close();
180
181    // table not exists
182    assertThrows(TableNotFoundException.class,
183      () -> FutureUtils.get(admin.modifyTableStoreFileTracker(TableName.valueOf("whatever"),
184        StoreFileTrackerFactory.Trackers.FILE.name())));
185    // family not exists
186    assertThrows(NoSuchColumnFamilyException.class,
187      () -> FutureUtils.get(admin.modifyColumnFamilyStoreFileTracker(tableName,
188        Bytes.toBytes("not_exists"), StoreFileTrackerFactory.Trackers.FILE.name())));
189    // to migration
190    assertThrows(DoNotRetryIOException.class, () -> FutureUtils.get(admin
191      .modifyTableStoreFileTracker(tableName, StoreFileTrackerFactory.Trackers.MIGRATION.name())));
192    // disabled
193    admin.disableTable(tableName).join();
194    assertThrows(TableNotEnabledException.class, () -> FutureUtils.get(
195      admin.modifyTableStoreFileTracker(tableName, StoreFileTrackerFactory.Trackers.FILE.name())));
196  }
197}