HBASE-26921 Rewrite the counting cells part in TestMultiVersions (#4316)
[hbase.git] / hbase-server / src / test / java / org / apache / hadoop / hbase / regionserver / TestRecoveredEdits.java
blobcb8ec4fcf1464292db2891f4c5eaa53ebffe07e0
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org.apache.hadoop.hbase.regionserver;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.fs.FileSystem;
28 import org.apache.hadoop.fs.Path;
29 import org.apache.hadoop.hbase.Cell;
30 import org.apache.hadoop.hbase.CellComparatorImpl;
31 import org.apache.hadoop.hbase.HBaseClassTestRule;
32 import org.apache.hadoop.hbase.HBaseTestingUtil;
33 import org.apache.hadoop.hbase.HConstants;
34 import org.apache.hadoop.hbase.MemoryCompactionPolicy;
35 import org.apache.hadoop.hbase.PrivateCellUtil;
36 import org.apache.hadoop.hbase.TableName;
37 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
38 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
39 import org.apache.hadoop.hbase.client.RegionInfo;
40 import org.apache.hadoop.hbase.client.RegionInfoBuilder;
41 import org.apache.hadoop.hbase.client.Scan;
42 import org.apache.hadoop.hbase.client.TableDescriptor;
43 import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
44 import org.apache.hadoop.hbase.io.hfile.BlockCache;
45 import org.apache.hadoop.hbase.io.hfile.BlockCacheFactory;
46 import org.apache.hadoop.hbase.testclassification.MediumTests;
47 import org.apache.hadoop.hbase.util.Bytes;
48 import org.apache.hadoop.hbase.util.CommonFSUtils;
49 import org.apache.hadoop.hbase.util.FSUtils;
50 import org.apache.hadoop.hbase.wal.WAL;
51 import org.apache.hadoop.hbase.wal.WALEdit;
52 import org.apache.hadoop.hbase.wal.WALFactory;
53 import org.apache.hadoop.hbase.wal.WALKey;
54 import org.apache.hadoop.hbase.wal.WALSplitUtil;
55 import org.junit.BeforeClass;
56 import org.junit.ClassRule;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.junit.experimental.categories.Category;
60 import org.junit.rules.TestName;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
64 /**
65 * Tests around replay of recovered.edits content.
67 @Category({MediumTests.class})
68 public class TestRecoveredEdits {
70 @ClassRule
71 public static final HBaseClassTestRule CLASS_RULE =
72 HBaseClassTestRule.forClass(TestRecoveredEdits.class);
74 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
75 private static final Logger LOG = LoggerFactory.getLogger(TestRecoveredEdits.class);
77 private static BlockCache blockCache;
79 @Rule public TestName testName = new TestName();
81 /**
82 * Path to a recovered.edits file in hbase-server test resources folder.
83 * This is a little fragile getting this path to a file of 10M of edits.
85 @SuppressWarnings("checkstyle:VisibilityModifier")
86 public static final Path RECOVEREDEDITS_PATH = new Path(
87 System.getProperty("test.build.classes", "target/test-classes"),
88 "0000000000000016310");
90 /**
91 * Name of table referenced by edits in the recovered.edits file.
93 public static final String RECOVEREDEDITS_TABLENAME = "IntegrationTestBigLinkedList";
95 /**
96 * Column family referenced by edits in the recovered.edits file.
98 public static final byte [] RECOVEREDEDITS_COLUMNFAMILY = Bytes.toBytes("meta");
99 public static final byte[][] RECOVEREDITS_COLUMNFAMILY_ARRAY =
100 new byte[][] {RECOVEREDEDITS_COLUMNFAMILY};
101 public static final ColumnFamilyDescriptor RECOVEREDEDITS_CFD =
102 ColumnFamilyDescriptorBuilder.newBuilder(RECOVEREDEDITS_COLUMNFAMILY).build();
105 * Name of table mentioned edits from recovered.edits
107 @BeforeClass
108 public static void setUpBeforeClass() throws Exception {
109 blockCache = BlockCacheFactory.createBlockCache(TEST_UTIL.getConfiguration());
113 * HBASE-12782 ITBLL fails for me if generator does anything but 5M per maptask.
114 * Create a region. Close it. Then copy into place a file to replay, one that is bigger than
115 * configured flush size so we bring on lots of flushes. Then reopen and confirm all edits
116 * made it in.
118 @Test
119 public void testReplayWorksThoughLotsOfFlushing() throws IOException {
120 for (MemoryCompactionPolicy policy : MemoryCompactionPolicy.values()) {
121 testReplayWorksWithMemoryCompactionPolicy(policy);
125 private void testReplayWorksWithMemoryCompactionPolicy(MemoryCompactionPolicy policy) throws
126 IOException {
127 Configuration conf = new Configuration(TEST_UTIL.getConfiguration());
128 // Set it so we flush every 1M or so. Thats a lot.
129 conf.setInt(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, 1024*1024);
130 conf.set(CompactingMemStore.COMPACTING_MEMSTORE_TYPE_KEY, String.valueOf(policy).toLowerCase());
131 TableDescriptor tableDescriptor = TableDescriptorBuilder.
132 newBuilder(TableName.valueOf(testName.getMethodName())).
133 setColumnFamily(RECOVEREDEDITS_CFD) .build();
134 RegionInfo hri = RegionInfoBuilder.newBuilder(tableDescriptor.getTableName()).build();
135 final String encodedRegionName = hri.getEncodedName();
136 Path hbaseRootDir = TEST_UTIL.getDataTestDir();
137 FileSystem fs = FileSystem.get(TEST_UTIL.getConfiguration());
138 Path tableDir = CommonFSUtils.getTableDir(hbaseRootDir, tableDescriptor.getTableName());
139 HRegionFileSystem hrfs =
140 new HRegionFileSystem(TEST_UTIL.getConfiguration(), fs, tableDir, hri);
141 if (fs.exists(hrfs.getRegionDir())) {
142 LOG.info("Region directory already exists. Deleting.");
143 fs.delete(hrfs.getRegionDir(), true);
145 HRegion region = HBaseTestingUtil
146 .createRegionAndWAL(hri, hbaseRootDir, conf, tableDescriptor, blockCache);
147 assertEquals(encodedRegionName, region.getRegionInfo().getEncodedName());
148 List<String> storeFiles = region.getStoreFileList(RECOVEREDITS_COLUMNFAMILY_ARRAY);
149 // There should be no store files.
150 assertTrue(storeFiles.isEmpty());
151 region.close();
152 Path regionDir = FSUtils.getRegionDirFromRootDir(hbaseRootDir, hri);
153 Path recoveredEditsDir = WALSplitUtil.getRegionDirRecoveredEditsDir(regionDir);
154 // Copy this file under the region's recovered.edits dir so it is replayed on reopen.
155 Path destination = new Path(recoveredEditsDir, RECOVEREDEDITS_PATH.getName());
156 fs.copyToLocalFile(RECOVEREDEDITS_PATH, destination);
157 assertTrue(fs.exists(destination));
158 // Now the file 0000000000000016310 is under recovered.edits, reopen the region to replay.
159 region = HRegion.openHRegion(region, null);
160 assertEquals(encodedRegionName, region.getRegionInfo().getEncodedName());
161 storeFiles = region.getStoreFileList(RECOVEREDITS_COLUMNFAMILY_ARRAY);
162 // Our 0000000000000016310 is 10MB. Most of the edits are for one region. Lets assume that if
163 // we flush at 1MB, that there are at least 3 flushed files that are there because of the
164 // replay of edits.
165 if(policy == MemoryCompactionPolicy.EAGER || policy == MemoryCompactionPolicy.ADAPTIVE) {
166 assertTrue("Files count=" + storeFiles.size(), storeFiles.size() >= 1);
167 } else {
168 assertTrue("Files count=" + storeFiles.size(), storeFiles.size() > 10);
170 // Now verify all edits made it into the region.
171 int count = verifyAllEditsMadeItIn(fs, conf, RECOVEREDEDITS_PATH, region);
172 assertTrue(count > 0);
173 LOG.info("Checked " + count + " edits made it in");
177 * @return Return how many edits seen.
179 // Used by TestWALPlayer over in hbase-mapreduce too.
180 public static int verifyAllEditsMadeItIn(final FileSystem fs, final Configuration conf,
181 final Path edits, final HRegion region) throws IOException {
182 int count = 0;
183 // Read all cells from recover edits
184 List<Cell> walCells = new ArrayList<>();
185 try (WAL.Reader reader = WALFactory.createReader(fs, edits, conf)) {
186 WAL.Entry entry;
187 while ((entry = reader.next()) != null) {
188 WALKey key = entry.getKey();
189 WALEdit val = entry.getEdit();
190 count++;
191 // Check this edit is for this region.
192 if (!Bytes.equals(key.getEncodedRegionName(),
193 region.getRegionInfo().getEncodedNameAsBytes())) {
194 continue;
196 Cell previous = null;
197 for (Cell cell : val.getCells()) {
198 if (WALEdit.isMetaEditFamily(cell)) {
199 continue;
201 if (previous != null && CellComparatorImpl.COMPARATOR.compareRows(previous, cell) == 0) {
202 continue;
204 previous = cell;
205 walCells.add(cell);
210 // Read all cells from region
211 List<Cell> regionCells = new ArrayList<>();
212 try (RegionScanner scanner = region.getScanner(new Scan())) {
213 List<Cell> tmpCells;
214 do {
215 tmpCells = new ArrayList<>();
216 scanner.nextRaw(tmpCells);
217 regionCells.addAll(tmpCells);
218 } while (!tmpCells.isEmpty());
221 Collections.sort(walCells, CellComparatorImpl.COMPARATOR);
222 int found = 0;
223 for (int i = 0, j = 0; i < walCells.size() && j < regionCells.size(); ) {
224 int compareResult = PrivateCellUtil
225 .compareKeyIgnoresMvcc(CellComparatorImpl.COMPARATOR, walCells.get(i),
226 regionCells.get(j));
227 if (compareResult == 0) {
228 i++;
229 j++;
230 found++;
231 } else if (compareResult > 0) {
232 j++;
233 } else {
234 i++;
237 assertEquals("Only found " + found + " cells in region, but there are " + walCells.size() +
238 " cells in recover edits", found, walCells.size());
239 return count;