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
;
65 * Tests around replay of recovered.edits content.
67 @Category({MediumTests
.class})
68 public class TestRecoveredEdits
{
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();
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");
91 * Name of table referenced by edits in the recovered.edits file.
93 public static final String RECOVEREDEDITS_TABLENAME
= "IntegrationTestBigLinkedList";
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
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
119 public void testReplayWorksThoughLotsOfFlushing() throws IOException
{
120 for (MemoryCompactionPolicy policy
: MemoryCompactionPolicy
.values()) {
121 testReplayWorksWithMemoryCompactionPolicy(policy
);
125 private void testReplayWorksWithMemoryCompactionPolicy(MemoryCompactionPolicy policy
) throws
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());
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
165 if(policy
== MemoryCompactionPolicy
.EAGER
|| policy
== MemoryCompactionPolicy
.ADAPTIVE
) {
166 assertTrue("Files count=" + storeFiles
.size(), storeFiles
.size() >= 1);
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
{
183 // Read all cells from recover edits
184 List
<Cell
> walCells
= new ArrayList
<>();
185 try (WAL
.Reader reader
= WALFactory
.createReader(fs
, edits
, conf
)) {
187 while ((entry
= reader
.next()) != null) {
188 WALKey key
= entry
.getKey();
189 WALEdit val
= entry
.getEdit();
191 // Check this edit is for this region.
192 if (!Bytes
.equals(key
.getEncodedRegionName(),
193 region
.getRegionInfo().getEncodedNameAsBytes())) {
196 Cell previous
= null;
197 for (Cell cell
: val
.getCells()) {
198 if (WALEdit
.isMetaEditFamily(cell
)) {
201 if (previous
!= null && CellComparatorImpl
.COMPARATOR
.compareRows(previous
, cell
) == 0) {
210 // Read all cells from region
211 List
<Cell
> regionCells
= new ArrayList
<>();
212 try (RegionScanner scanner
= region
.getScanner(new Scan())) {
215 tmpCells
= new ArrayList
<>();
216 scanner
.nextRaw(tmpCells
);
217 regionCells
.addAll(tmpCells
);
218 } while (!tmpCells
.isEmpty());
221 Collections
.sort(walCells
, CellComparatorImpl
.COMPARATOR
);
223 for (int i
= 0, j
= 0; i
< walCells
.size() && j
< regionCells
.size(); ) {
224 int compareResult
= PrivateCellUtil
225 .compareKeyIgnoresMvcc(CellComparatorImpl
.COMPARATOR
, walCells
.get(i
),
227 if (compareResult
== 0) {
231 } else if (compareResult
> 0) {
237 assertEquals("Only found " + found
+ " cells in region, but there are " + walCells
.size() +
238 " cells in recover edits", found
, walCells
.size());