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.regionserver; 019 020import static java.util.Arrays.asList; 021import static org.junit.jupiter.api.Assertions.assertThrows; 022import static org.mockito.ArgumentMatchers.any; 023import static org.mockito.ArgumentMatchers.anyLong; 024import static org.mockito.Mockito.verify; 025import static org.mockito.Mockito.when; 026import static org.mockito.hamcrest.MockitoHamcrest.argThat; 027 028import java.io.FileNotFoundException; 029import java.io.IOException; 030import java.util.ArrayList; 031import java.util.List; 032import org.apache.hadoop.fs.Path; 033import org.apache.hadoop.hbase.DoNotRetryIOException; 034import org.apache.hadoop.hbase.HBaseParameterizedTestTemplate; 035import org.apache.hadoop.hbase.TableName; 036import org.apache.hadoop.hbase.testclassification.SmallTests; 037import org.apache.hadoop.hbase.util.Pair; 038import org.apache.hadoop.hbase.wal.WALEdit; 039import org.apache.hadoop.hbase.wal.WALKeyImpl; 040import org.junit.jupiter.api.Tag; 041import org.junit.jupiter.api.TestTemplate; 042import org.mockito.invocation.InvocationOnMock; 043import org.mockito.stubbing.Answer; 044 045/** 046 * This class attempts to unit test bulk HLog loading. 047 */ 048@Tag(SmallTests.TAG) 049@HBaseParameterizedTestTemplate(name = "{index}: useFileBasedSFT={0}") 050public class TestBulkLoad extends TestBulkloadBase { 051 052 public TestBulkLoad(boolean useFileBasedSFT) { 053 super(useFileBasedSFT); 054 } 055 056 @TestTemplate 057 public void verifyBulkLoadEvent() throws IOException { 058 TableName tableName = TableName.valueOf("test", "test"); 059 List<Pair<byte[], String>> familyPaths = withFamilyPathsFor(family1); 060 byte[] familyName = familyPaths.get(0).getFirst(); 061 String storeFileName = familyPaths.get(0).getSecond(); 062 storeFileName = (new Path(storeFileName)).getName(); 063 List<String> storeFileNames = new ArrayList<>(); 064 storeFileNames.add(storeFileName); 065 when(log.appendMarker(any(), any(), 066 argThat(bulkLogWalEdit(WALEdit.BULK_LOAD, tableName.toBytes(), familyName, storeFileNames)))) 067 .thenAnswer(new Answer() { 068 @Override 069 public Object answer(InvocationOnMock invocation) { 070 WALKeyImpl walKey = invocation.getArgument(1); 071 MultiVersionConcurrencyControl mvcc = walKey.getMvcc(); 072 if (mvcc != null) { 073 MultiVersionConcurrencyControl.WriteEntry we = mvcc.begin(); 074 walKey.setWriteEntry(we); 075 } 076 return 01L; 077 } 078 }); 079 testRegionWithFamiliesAndSpecifiedTableName(tableName, family1).bulkLoadHFiles(familyPaths, 080 false, null); 081 verify(log).sync(anyLong()); 082 } 083 084 @TestTemplate 085 public void bulkHLogShouldThrowNoErrorAndWriteMarkerWithBlankInput() throws IOException { 086 testRegionWithFamilies(family1).bulkLoadHFiles(new ArrayList<>(), false, null); 087 } 088 089 @TestTemplate 090 public void shouldBulkLoadSingleFamilyHLog() throws IOException { 091 when(log.appendMarker(any(), any(), argThat(bulkLogWalEditType(WALEdit.BULK_LOAD)))) 092 .thenAnswer(new Answer() { 093 @Override 094 public Object answer(InvocationOnMock invocation) { 095 WALKeyImpl walKey = invocation.getArgument(1); 096 MultiVersionConcurrencyControl mvcc = walKey.getMvcc(); 097 if (mvcc != null) { 098 MultiVersionConcurrencyControl.WriteEntry we = mvcc.begin(); 099 walKey.setWriteEntry(we); 100 } 101 return 01L; 102 } 103 }); 104 testRegionWithFamilies(family1).bulkLoadHFiles(withFamilyPathsFor(family1), false, null); 105 verify(log).sync(anyLong()); 106 } 107 108 @TestTemplate 109 public void shouldBulkLoadManyFamilyHLog() throws IOException { 110 when(log.appendMarker(any(), any(), argThat(bulkLogWalEditType(WALEdit.BULK_LOAD)))) 111 .thenAnswer(new Answer() { 112 @Override 113 public Object answer(InvocationOnMock invocation) { 114 WALKeyImpl walKey = invocation.getArgument(1); 115 MultiVersionConcurrencyControl mvcc = walKey.getMvcc(); 116 if (mvcc != null) { 117 MultiVersionConcurrencyControl.WriteEntry we = mvcc.begin(); 118 walKey.setWriteEntry(we); 119 } 120 return 1L; 121 } 122 }); 123 testRegionWithFamilies(family1, family2).bulkLoadHFiles(withFamilyPathsFor(family1, family2), 124 false, null); 125 verify(log).sync(anyLong()); 126 } 127 128 @TestTemplate 129 public void shouldBulkLoadManyFamilyHLogEvenWhenTableNameNamespaceSpecified() throws IOException { 130 when(log.appendMarker(any(), any(), argThat(bulkLogWalEditType(WALEdit.BULK_LOAD)))) 131 .thenAnswer(new Answer() { 132 @Override 133 public Object answer(InvocationOnMock invocation) { 134 WALKeyImpl walKey = invocation.getArgument(1); 135 MultiVersionConcurrencyControl mvcc = walKey.getMvcc(); 136 if (mvcc != null) { 137 MultiVersionConcurrencyControl.WriteEntry we = mvcc.begin(); 138 walKey.setWriteEntry(we); 139 } 140 return 1L; 141 } 142 }); 143 TableName tableName = TableName.valueOf("test", "test"); 144 testRegionWithFamiliesAndSpecifiedTableName(tableName, family1, family2) 145 .bulkLoadHFiles(withFamilyPathsFor(family1, family2), false, null); 146 verify(log).sync(anyLong()); 147 } 148 149 @TestTemplate 150 public void shouldCrashIfBulkLoadFamiliesNotInTable() throws IOException { 151 assertThrows(DoNotRetryIOException.class, () -> testRegionWithFamilies(family1) 152 .bulkLoadHFiles(withFamilyPathsFor(family1, family2), false, null)); 153 } 154 155 // after HBASE-24021 will throw DoNotRetryIOException, not MultipleIOException 156 @TestTemplate 157 public void shouldCrashIfBulkLoadMultiFamiliesNotInTable() throws IOException { 158 assertThrows(DoNotRetryIOException.class, () -> testRegionWithFamilies(family1) 159 .bulkLoadHFiles(withFamilyPathsFor(family1, family2, family3), false, null)); 160 } 161 162 @TestTemplate 163 public void bulkHLogShouldThrowErrorWhenFamilySpecifiedAndHFileExistsButNotInTableDescriptor() 164 throws IOException { 165 assertThrows(DoNotRetryIOException.class, 166 () -> testRegionWithFamilies().bulkLoadHFiles(withFamilyPathsFor(family1), false, null)); 167 } 168 169 @TestTemplate 170 public void shouldThrowErrorIfBadFamilySpecifiedAsFamilyPath() throws IOException { 171 assertThrows(DoNotRetryIOException.class, () -> testRegionWithFamilies() 172 .bulkLoadHFiles(asList(withInvalidColumnFamilyButProperHFileLocation(family1)), false, null)); 173 } 174 175 @TestTemplate 176 public void shouldThrowErrorIfHFileDoesNotExist() throws IOException { 177 List<Pair<byte[], String>> list = asList(withMissingHFileForFamily(family1)); 178 assertThrows(FileNotFoundException.class, 179 () -> testRegionWithFamilies(family1).bulkLoadHFiles(list, false, null)); 180 } 181 182 // after HBASE-24021 will throw FileNotFoundException, not MultipleIOException 183 @TestTemplate 184 public void shouldThrowErrorIfMultiHFileDoesNotExist() throws IOException { 185 List<Pair<byte[], String>> list = new ArrayList<>(); 186 list.addAll(asList(withMissingHFileForFamily(family1))); 187 list.addAll(asList(withMissingHFileForFamily(family2))); 188 assertThrows(FileNotFoundException.class, 189 () -> testRegionWithFamilies(family1, family2).bulkLoadHFiles(list, false, null)); 190 } 191}