1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.hadoop.hbase.io.encoding;
18
19 import static org.junit.Assert.assertTrue;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Random;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.hbase.Cell;
32 import org.apache.hadoop.hbase.CellUtil;
33 import org.apache.hadoop.hbase.HBaseTestingUtility;
34 import org.apache.hadoop.hbase.HColumnDescriptor;
35 import org.apache.hadoop.hbase.HConstants;
36 import org.apache.hadoop.hbase.HTableDescriptor;
37 import org.apache.hadoop.hbase.testclassification.LargeTests;
38 import org.apache.hadoop.hbase.TableName;
39 import org.apache.hadoop.hbase.client.Admin;
40 import org.apache.hadoop.hbase.client.Connection;
41 import org.apache.hadoop.hbase.client.ConnectionFactory;
42 import org.apache.hadoop.hbase.client.Durability;
43 import org.apache.hadoop.hbase.client.Get;
44 import org.apache.hadoop.hbase.client.HBaseAdmin;
45 import org.apache.hadoop.hbase.client.HTable;
46 import org.apache.hadoop.hbase.client.Put;
47 import org.apache.hadoop.hbase.client.Result;
48 import org.apache.hadoop.hbase.client.Table;
49 import org.apache.hadoop.hbase.regionserver.HRegionServer;
50 import org.apache.hadoop.hbase.util.Bytes;
51 import org.apache.hadoop.hbase.util.Threads;
52 import org.apache.hadoop.hbase.zookeeper.ZKAssign;
53 import org.junit.AfterClass;
54 import org.junit.BeforeClass;
55 import org.junit.Test;
56 import org.junit.experimental.categories.Category;
57
58
59
60
61 @Category(LargeTests.class)
62 public class TestChangingEncoding {
63 private static final Log LOG = LogFactory.getLog(TestChangingEncoding.class);
64 static final String CF = "EncodingTestCF";
65 static final byte[] CF_BYTES = Bytes.toBytes(CF);
66
67 private static final int NUM_ROWS_PER_BATCH = 100;
68 private static final int NUM_COLS_PER_ROW = 20;
69
70 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
71 private static final Configuration conf = TEST_UTIL.getConfiguration();
72
73 private static final int TIMEOUT_MS = 600000;
74
75 private HColumnDescriptor hcd;
76
77 private TableName tableName;
78 private static final List<DataBlockEncoding> ENCODINGS_TO_ITERATE =
79 createEncodingsToIterate();
80
81 private static final List<DataBlockEncoding> createEncodingsToIterate() {
82 List<DataBlockEncoding> encodings = new ArrayList<DataBlockEncoding>(
83 Arrays.asList(DataBlockEncoding.values()));
84 encodings.add(DataBlockEncoding.NONE);
85 return Collections.unmodifiableList(encodings);
86 }
87
88
89 private int numBatchesWritten;
90
91 private void prepareTest(String testId) throws IOException {
92 tableName = TableName.valueOf("test_table_" + testId);
93 HTableDescriptor htd = new HTableDescriptor(tableName);
94 hcd = new HColumnDescriptor(CF);
95 htd.addFamily(hcd);
96 try (Admin admin = TEST_UTIL.getConnection().getAdmin()) {
97 admin.createTable(htd);
98 }
99 numBatchesWritten = 0;
100 }
101
102 @BeforeClass
103 public static void setUpBeforeClass() throws Exception {
104
105 conf.setInt(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, 1024 * 1024);
106
107
108
109
110 conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
111 "org.apache.hadoop.hbase.regionserver.DisabledRegionSplitPolicy");
112 conf.setBoolean("hbase.online.schema.update.enable", true);
113 TEST_UTIL.startMiniCluster();
114 }
115
116 @AfterClass
117 public static void tearDownAfterClass() throws Exception {
118 TEST_UTIL.shutdownMiniCluster();
119 }
120
121 private static byte[] getRowKey(int batchId, int i) {
122 return Bytes.toBytes("batch" + batchId + "_row" + i);
123 }
124
125 private static byte[] getQualifier(int j) {
126 return Bytes.toBytes("col" + j);
127 }
128
129 private static byte[] getValue(int batchId, int i, int j) {
130 return Bytes.toBytes("value_for_" + Bytes.toString(getRowKey(batchId, i))
131 + "_col" + j);
132 }
133
134 static void writeTestDataBatch(Configuration conf, TableName tableName,
135 int batchId) throws Exception {
136 LOG.debug("Writing test data batch " + batchId);
137 List<Put> puts = new ArrayList<>();
138 for (int i = 0; i < NUM_ROWS_PER_BATCH; ++i) {
139 Put put = new Put(getRowKey(batchId, i));
140 for (int j = 0; j < NUM_COLS_PER_ROW; ++j) {
141 put.add(CF_BYTES, getQualifier(j),
142 getValue(batchId, i, j));
143 }
144 put.setDurability(Durability.SKIP_WAL);
145 puts.add(put);
146 }
147 try (Connection conn = ConnectionFactory.createConnection(conf);
148 Table table = conn.getTable(tableName)) {
149 table.put(puts);
150 }
151 }
152
153 static void verifyTestDataBatch(Configuration conf, TableName tableName,
154 int batchId) throws Exception {
155 LOG.debug("Verifying test data batch " + batchId);
156 Table table = new HTable(conf, tableName);
157 for (int i = 0; i < NUM_ROWS_PER_BATCH; ++i) {
158 Get get = new Get(getRowKey(batchId, i));
159 Result result = table.get(get);
160 for (int j = 0; j < NUM_COLS_PER_ROW; ++j) {
161 Cell kv = result.getColumnLatestCell(CF_BYTES, getQualifier(j));
162 assertTrue(CellUtil.matchingValue(kv, getValue(batchId, i, j)));
163 }
164 }
165 table.close();
166 }
167
168 private void writeSomeNewData() throws Exception {
169 writeTestDataBatch(conf, tableName, numBatchesWritten);
170 ++numBatchesWritten;
171 }
172
173 private void verifyAllData() throws Exception {
174 for (int i = 0; i < numBatchesWritten; ++i) {
175 verifyTestDataBatch(conf, tableName, i);
176 }
177 }
178
179 private void setEncodingConf(DataBlockEncoding encoding,
180 boolean onlineChange) throws Exception {
181 LOG.debug("Setting CF encoding to " + encoding + " (ordinal="
182 + encoding.ordinal() + "), onlineChange=" + onlineChange);
183 hcd.setDataBlockEncoding(encoding);
184 try (Admin admin = TEST_UTIL.getConnection().getAdmin()) {
185 if (!onlineChange) {
186 admin.disableTable(tableName);
187 }
188 admin.modifyColumn(tableName, hcd);
189 if (!onlineChange) {
190 admin.enableTable(tableName);
191 }
192 }
193
194
195
196
197 ZKAssign.blockUntilNoRIT(TEST_UTIL.getZooKeeperWatcher());
198 }
199
200 @Test(timeout=TIMEOUT_MS)
201 public void testChangingEncoding() throws Exception {
202 prepareTest("ChangingEncoding");
203 for (boolean onlineChange : new boolean[]{false, true}) {
204 for (DataBlockEncoding encoding : ENCODINGS_TO_ITERATE) {
205 setEncodingConf(encoding, onlineChange);
206 writeSomeNewData();
207 verifyAllData();
208 }
209 }
210 }
211
212 @Test(timeout=TIMEOUT_MS)
213 public void testChangingEncodingWithCompaction() throws Exception {
214 prepareTest("ChangingEncodingWithCompaction");
215 for (boolean onlineChange : new boolean[]{false, true}) {
216 for (DataBlockEncoding encoding : ENCODINGS_TO_ITERATE) {
217 setEncodingConf(encoding, onlineChange);
218 writeSomeNewData();
219 verifyAllData();
220 compactAndWait();
221 verifyAllData();
222 }
223 }
224 }
225
226 private void compactAndWait() throws IOException, InterruptedException {
227 LOG.debug("Compacting table " + tableName);
228 HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
229 HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
230 admin.majorCompact(tableName);
231
232
233 final long maxWaitime = System.currentTimeMillis() + 500;
234 boolean cont;
235 do {
236 cont = rs.compactSplitThread.getCompactionQueueSize() == 0;
237 Threads.sleep(1);
238 } while (cont && System.currentTimeMillis() < maxWaitime);
239
240 while (rs.compactSplitThread.getCompactionQueueSize() > 0) {
241 Threads.sleep(1);
242 }
243 LOG.debug("Compaction queue size reached 0, continuing");
244 }
245
246 @Test
247 public void testCrazyRandomChanges() throws Exception {
248 prepareTest("RandomChanges");
249 Random rand = new Random(2934298742974297L);
250 for (int i = 0; i < 20; ++i) {
251 int encodingOrdinal = rand.nextInt(DataBlockEncoding.values().length);
252 DataBlockEncoding encoding = DataBlockEncoding.values()[encodingOrdinal];
253 setEncodingConf(encoding, rand.nextBoolean());
254 writeSomeNewData();
255 verifyAllData();
256 }
257 }
258
259 }