Skip to content

Commit 0718094

Browse files
author
Prathyusha Garre
committed
HBASE-27826 Add FSFT implementations for Virtual links and enable them as part of SplitProcedure
1 parent 39f5903 commit 0718094

29 files changed

Lines changed: 535 additions & 183 deletions

hbase-protocol-shaded/src/main/protobuf/server/region/StoreFileTracker.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ option java_generic_services = true;
2525
option java_generate_equals_and_hash = true;
2626
option optimize_for = SPEED;
2727

28+
import "server/io/FS.proto";
2829
message StoreFileEntry {
2930
required string name = 1;
3031
required uint64 size = 2;
32+
optional Reference reference = 3;
3133
}
3234

3335
message StoreFileList {

hbase-server/src/main/java/org/apache/hadoop/hbase/io/HFileLink.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public class HFileLink extends FileLink {
8181
* The pattern should be used for hfile and reference links that can be found in
8282
* /hbase/table/region/family/
8383
*/
84-
private static final Pattern REF_OR_HFILE_LINK_PATTERN =
84+
public static final Pattern REF_OR_HFILE_LINK_PATTERN =
8585
Pattern.compile(String.format("^(?:(%s)(?:=))?(%s)=(%s)-(.+)$", TableName.VALID_NAMESPACE_REGEX,
8686
TableName.VALID_TABLE_QUALIFIER_REGEX, RegionInfoBuilder.ENCODED_REGION_NAME_REGEX));
8787

hbase-server/src/main/java/org/apache/hadoop/hbase/io/Reference.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public class Reference {
5656
* For split HStoreFiles, it specifies if the file covers the lower half or the upper half of the
5757
* key range
5858
*/
59-
static enum Range {
59+
public static enum Range {
6060
/** HStoreFile contains upper half of key range */
6161
top,
6262
/** HStoreFile contains lower half of key range */

hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/MergeTableRegionsProcedure.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ private void createMergedRegion(final MasterProcedureEnv env) throws IOException
605605
final MasterFileSystem mfs = env.getMasterServices().getMasterFileSystem();
606606
final Path tableDir = CommonFSUtils.getTableDir(mfs.getRootDir(), regionsToMerge[0].getTable());
607607
final FileSystem fs = mfs.getFileSystem();
608-
List<Path> mergedFiles = new ArrayList<>();
608+
List<StoreFileInfo> mergedFiles = new ArrayList<StoreFileInfo>();
609609
HRegionFileSystem mergeRegionFs = HRegionFileSystem
610610
.createRegionOnFileSystem(env.getMasterConfiguration(), fs, tableDir, mergedRegion);
611611

@@ -622,11 +622,11 @@ private void createMergedRegion(final MasterProcedureEnv env) throws IOException
622622
.setState(State.MERGING_NEW);
623623
}
624624

625-
private List<Path> mergeStoreFiles(MasterProcedureEnv env, HRegionFileSystem regionFs,
625+
private List<StoreFileInfo> mergeStoreFiles(MasterProcedureEnv env, HRegionFileSystem regionFs,
626626
HRegionFileSystem mergeRegionFs, RegionInfo mergedRegion) throws IOException {
627627
final TableDescriptor htd =
628628
env.getMasterServices().getTableDescriptors().get(mergedRegion.getTable());
629-
List<Path> mergedFiles = new ArrayList<>();
629+
List<StoreFileInfo> mergedFiles = new ArrayList<StoreFileInfo>();
630630
for (ColumnFamilyDescriptor hcd : htd.getColumnFamilies()) {
631631
String family = hcd.getNameAsString();
632632
StoreFileTracker tracker =
@@ -643,7 +643,7 @@ private List<Path> mergeStoreFiles(MasterProcedureEnv env, HRegionFileSystem reg
643643
// is running in a regionserver's Store context, or we might not be able
644644
// to read the hfiles.
645645
storeFileInfo.setConf(storeConfiguration);
646-
Path refFile = mergeRegionFs.mergeStoreFile(regionFs.getRegionInfo(), family,
646+
StoreFileInfo refFile = mergeRegionFs.mergeStoreFile(regionFs.getRegionInfo(), family,
647647
new HStoreFile(storeFileInfo, hcd.getBloomFilterType(), CacheConfig.DISABLED), tracker);
648648
mergedFiles.add(refFile);
649649
}

hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/SplitTableRegionProcedure.java

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@
7171
import org.apache.hadoop.hbase.util.Bytes;
7272
import org.apache.hadoop.hbase.util.CommonFSUtils;
7373
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
74-
import org.apache.hadoop.hbase.util.FSUtils;
7574
import org.apache.hadoop.hbase.util.Pair;
7675
import org.apache.hadoop.hbase.util.Threads;
7776
import org.apache.hadoop.hbase.wal.WALSplitUtil;
@@ -660,20 +659,46 @@ public void createDaughterRegions(final MasterProcedureEnv env) throws IOExcepti
660659
HRegionFileSystem regionFs = HRegionFileSystem.openRegionFromFileSystem(
661660
env.getMasterConfiguration(), fs, tabledir, getParentRegion(), false);
662661
regionFs.createSplitsDir(daughterOneRI, daughterTwoRI);
662+
Pair<List<StoreFileInfo>, List<StoreFileInfo>> expectedReferences =
663+
splitStoreFiles(env, regionFs);
664+
final ExecutorService threadPool = Executors.newFixedThreadPool(2,
665+
new ThreadFactoryBuilder().setNameFormat("RegionCommitter-pool-%d").setDaemon(true)
666+
.setUncaughtExceptionHandler(Threads.LOGGING_EXCEPTION_HANDLER).build());
667+
threadPool.submit(new Callable<Path>() {
668+
@Override
669+
public Path call() throws IOException {
670+
return regionFs.commitDaughterRegion(daughterOneRI, expectedReferences.getFirst(), env);
671+
}
672+
});
673+
threadPool.submit(new Callable<Path>() {
674+
@Override
675+
public Path call() throws IOException {
676+
return regionFs.commitDaughterRegion(daughterTwoRI, expectedReferences.getSecond(), env);
677+
}
678+
});
679+
// Shutdown the pool
680+
threadPool.shutdown();
663681

664-
Pair<List<Path>, List<Path>> expectedReferences = splitStoreFiles(env, regionFs);
665-
666-
assertSplitResultFilesCount(fs, expectedReferences.getFirst().size(),
667-
regionFs.getSplitsDir(daughterOneRI));
668-
regionFs.commitDaughterRegion(daughterOneRI, expectedReferences.getFirst(), env);
669-
assertSplitResultFilesCount(fs, expectedReferences.getFirst().size(),
670-
new Path(tabledir, daughterOneRI.getEncodedName()));
671-
672-
assertSplitResultFilesCount(fs, expectedReferences.getSecond().size(),
673-
regionFs.getSplitsDir(daughterTwoRI));
674-
regionFs.commitDaughterRegion(daughterTwoRI, expectedReferences.getSecond(), env);
675-
assertSplitResultFilesCount(fs, expectedReferences.getSecond().size(),
676-
new Path(tabledir, daughterTwoRI.getEncodedName()));
682+
Configuration conf = env.getMasterConfiguration();
683+
// Wait for all the tasks to finish.
684+
// When splits ran on the RegionServer, how-long-to-wait-configuration was named
685+
// hbase.regionserver.fileSplitTimeout. If set, use its value.
686+
long fileSplitTimeout = conf.getLong("hbase.master.fileSplitTimeout",
687+
conf.getLong("hbase.regionserver.fileSplitTimeout", 600000));
688+
try {
689+
boolean stillRunning = !threadPool.awaitTermination(fileSplitTimeout, TimeUnit.MILLISECONDS);
690+
if (stillRunning) {
691+
threadPool.shutdownNow();
692+
// wait for the thread to shutdown completely.
693+
while (!threadPool.isTerminated()) {
694+
Thread.sleep(50);
695+
}
696+
throw new IOException(
697+
"Took too long to split the" + " files and create the references, aborting split");
698+
}
699+
} catch (InterruptedException e) {
700+
throw (InterruptedIOException) new InterruptedIOException().initCause(e);
701+
}
677702
}
678703

679704
private void deleteDaughterRegions(final MasterProcedureEnv env) throws IOException {
@@ -689,8 +714,8 @@ private void deleteDaughterRegions(final MasterProcedureEnv env) throws IOExcept
689714
* Create Split directory
690715
* @param env MasterProcedureEnv
691716
*/
692-
private Pair<List<Path>, List<Path>> splitStoreFiles(final MasterProcedureEnv env,
693-
final HRegionFileSystem regionFs) throws IOException {
717+
private Pair<List<StoreFileInfo>, List<StoreFileInfo>> splitStoreFiles(
718+
final MasterProcedureEnv env, final HRegionFileSystem regionFs) throws IOException {
694719
final Configuration conf = env.getMasterConfiguration();
695720
TableDescriptor htd = env.getMasterServices().getTableDescriptors().get(getTableName());
696721
// The following code sets up a thread pool executor with as many slots as
@@ -745,7 +770,8 @@ private Pair<List<Path>, List<Path>> splitStoreFiles(final MasterProcedureEnv en
745770
final ExecutorService threadPool = Executors.newFixedThreadPool(maxThreads,
746771
new ThreadFactoryBuilder().setNameFormat("StoreFileSplitter-pool-%d").setDaemon(true)
747772
.setUncaughtExceptionHandler(Threads.LOGGING_EXCEPTION_HANDLER).build());
748-
final List<Future<Pair<Path, Path>>> futures = new ArrayList<Future<Pair<Path, Path>>>(nbFiles);
773+
final List<Future<Pair<StoreFileInfo, StoreFileInfo>>> futures =
774+
new ArrayList<Future<Pair<StoreFileInfo, StoreFileInfo>>>(nbFiles);
749775

750776
// Split each store file.
751777
for (Map.Entry<String, Collection<StoreFileInfo>> e : files.entrySet()) {
@@ -792,12 +818,12 @@ private Pair<List<Path>, List<Path>> splitStoreFiles(final MasterProcedureEnv en
792818
throw (InterruptedIOException) new InterruptedIOException().initCause(e);
793819
}
794820

795-
List<Path> daughterA = new ArrayList<>();
796-
List<Path> daughterB = new ArrayList<>();
821+
List<StoreFileInfo> daughterA = new ArrayList<>();
822+
List<StoreFileInfo> daughterB = new ArrayList<>();
797823
// Look for any exception
798-
for (Future<Pair<Path, Path>> future : futures) {
824+
for (Future<Pair<StoreFileInfo, StoreFileInfo>> future : futures) {
799825
try {
800-
Pair<Path, Path> p = future.get();
826+
Pair<StoreFileInfo, StoreFileInfo> p = future.get();
801827
if (p.getFirst() != null) {
802828
daughterA.add(p.getFirst());
803829
}
@@ -819,19 +845,8 @@ private Pair<List<Path>, List<Path>> splitStoreFiles(final MasterProcedureEnv en
819845
return new Pair<>(daughterA, daughterB);
820846
}
821847

822-
private void assertSplitResultFilesCount(final FileSystem fs,
823-
final int expectedSplitResultFileCount, Path dir) throws IOException {
824-
if (expectedSplitResultFileCount != 0) {
825-
int resultFileCount = FSUtils.getRegionReferenceAndLinkFileCount(fs, dir);
826-
if (expectedSplitResultFileCount != resultFileCount) {
827-
throw new IOException("Failing split. Didn't have expected reference and HFileLink files"
828-
+ ", expected=" + expectedSplitResultFileCount + ", actual=" + resultFileCount);
829-
}
830-
}
831-
}
832-
833-
private Pair<Path, Path> splitStoreFile(HRegionFileSystem regionFs, TableDescriptor htd,
834-
ColumnFamilyDescriptor hcd, HStoreFile sf) throws IOException {
848+
private Pair<StoreFileInfo, StoreFileInfo> splitStoreFile(HRegionFileSystem regionFs,
849+
TableDescriptor htd, ColumnFamilyDescriptor hcd, HStoreFile sf) throws IOException {
835850
if (LOG.isDebugEnabled()) {
836851
LOG.debug("pid=" + getProcId() + " splitting started for store file: " + sf.getPath()
837852
+ " for region: " + getParentRegion().getShortNameToLog());
@@ -847,22 +862,22 @@ private Pair<Path, Path> splitStoreFile(HRegionFileSystem regionFs, TableDescrip
847862
StoreFileTrackerFactory.create(regionFs.getFileSystem().getConf(), htd, hcd,
848863
HRegionFileSystem.create(regionFs.getFileSystem().getConf(), regionFs.getFileSystem(),
849864
regionFs.getTableDir(), daughterTwoRI));
850-
final Path path_first = regionFs.splitStoreFile(this.daughterOneRI, familyName, sf, splitRow,
851-
false, splitPolicy, daughterOneSft);
852-
final Path path_second = regionFs.splitStoreFile(this.daughterTwoRI, familyName, sf, splitRow,
853-
true, splitPolicy, daughterTwoSft);
865+
final StoreFileInfo sfiFirst = regionFs.splitStoreFile(this.daughterOneRI, familyName, sf,
866+
splitRow, false, splitPolicy, daughterOneSft);
867+
final StoreFileInfo sfiSecond = regionFs.splitStoreFile(this.daughterTwoRI, familyName, sf,
868+
splitRow, true, splitPolicy, daughterTwoSft);
854869
if (LOG.isDebugEnabled()) {
855870
LOG.debug("pid=" + getProcId() + " splitting complete for store file: " + sf.getPath()
856871
+ " for region: " + getParentRegion().getShortNameToLog());
857872
}
858-
return new Pair<Path, Path>(path_first, path_second);
873+
return new Pair<StoreFileInfo, StoreFileInfo>(sfiFirst, sfiSecond);
859874
}
860875

861876
/**
862877
* Utility class used to do the file splitting / reference writing in parallel instead of
863878
* sequentially.
864879
*/
865-
private class StoreFileSplitter implements Callable<Pair<Path, Path>> {
880+
private class StoreFileSplitter implements Callable<Pair<StoreFileInfo, StoreFileInfo>> {
866881
private final HRegionFileSystem regionFs;
867882
private final ColumnFamilyDescriptor hcd;
868883
private final HStoreFile sf;
@@ -883,7 +898,7 @@ public StoreFileSplitter(HRegionFileSystem regionFs, TableDescriptor htd,
883898
}
884899

885900
@Override
886-
public Pair<Path, Path> call() throws IOException {
901+
public Pair<StoreFileInfo, StoreFileInfo> call() throws IOException {
887902
return splitStoreFile(regionFs, htd, hcd, sf);
888903
}
889904
}

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HMobStore.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public class HMobStore extends HStore {
102102
// table, we need to find the original mob files by this table name. For details please see
103103
// cloning snapshot for mob files.
104104
private final byte[] refCellTags;
105+
private StoreFileTracker mobStoreSFT = null;
105106

106107
public HMobStore(final HRegion region, final ColumnFamilyDescriptor family,
107108
final Configuration confParam, boolean warmup) throws IOException {

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ void cleanupDaughterRegion(final RegionInfo regionInfo) throws IOException {
496496
* in the filesystem.
497497
* @param regionInfo daughter {@link org.apache.hadoop.hbase.client.RegionInfo}
498498
*/
499-
public Path commitDaughterRegion(final RegionInfo regionInfo, List<Path> allRegionFiles,
499+
public Path commitDaughterRegion(final RegionInfo regionInfo, List<StoreFileInfo> allRegionFiles,
500500
MasterProcedureEnv env) throws IOException {
501501
Path regionDir = this.getSplitsDir(regionInfo);
502502
if (fs.exists(regionDir)) {
@@ -511,21 +511,43 @@ public Path commitDaughterRegion(final RegionInfo regionInfo, List<Path> allRegi
511511
return regionDir;
512512
}
513513

514-
private void insertRegionFilesIntoStoreTracker(List<Path> allFiles, MasterProcedureEnv env,
515-
HRegionFileSystem regionFs) throws IOException {
514+
private void insertRegionFilesIntoStoreTracker(List<StoreFileInfo> allFiles,
515+
MasterProcedureEnv env, HRegionFileSystem regionFs) throws IOException {
516516
TableDescriptor tblDesc =
517517
env.getMasterServices().getTableDescriptors().get(regionInfo.getTable());
518518
// we need to map trackers per store
519519
Map<String, StoreFileTracker> trackerMap = new HashMap<>();
520520
// we need to map store files per store
521521
Map<String, List<StoreFileInfo>> fileInfoMap = new HashMap<>();
522-
for (Path file : allFiles) {
522+
for (StoreFileInfo sfi : allFiles) {
523+
Path file = sfi.getPath();
523524
String familyName = file.getParent().getName();
524525
trackerMap.computeIfAbsent(familyName, t -> StoreFileTrackerFactory.create(conf, tblDesc,
525526
tblDesc.getColumnFamily(Bytes.toBytes(familyName)), regionFs));
526527
fileInfoMap.computeIfAbsent(familyName, l -> new ArrayList<>());
527528
List<StoreFileInfo> infos = fileInfoMap.get(familyName);
528-
infos.add(trackerMap.get(familyName).getStoreFileInfo(file, true));
529+
infos.add(sfi);
530+
}
531+
for (Map.Entry<String, StoreFileTracker> entry : trackerMap.entrySet()) {
532+
entry.getValue().add(fileInfoMap.get(entry.getKey()));
533+
}
534+
}
535+
536+
private void insertRegionfilePathsIntoStoreTracker(List<StoreFileInfo> allFiles,
537+
MasterProcedureEnv env, HRegionFileSystem regionFs) throws IOException {
538+
TableDescriptor tblDesc =
539+
env.getMasterServices().getTableDescriptors().get(regionInfo.getTable());
540+
// we need to map trackers per store
541+
Map<String, StoreFileTracker> trackerMap = new HashMap<>();
542+
// we need to map store files per store
543+
Map<String, List<StoreFileInfo>> fileInfoMap = new HashMap<>();
544+
for (StoreFileInfo file : allFiles) {
545+
String familyName = file.getPath().getParent().getName();
546+
trackerMap.computeIfAbsent(familyName, t -> StoreFileTrackerFactory.create(conf, tblDesc,
547+
tblDesc.getColumnFamily(familyName.getBytes()), regionFs));
548+
fileInfoMap.computeIfAbsent(familyName, l -> new ArrayList<>());
549+
List<StoreFileInfo> infos = fileInfoMap.get(familyName);
550+
infos.add(file);
529551
}
530552
for (Map.Entry<String, StoreFileTracker> entry : trackerMap.entrySet()) {
531553
entry.getValue().add(fileInfoMap.get(entry.getKey()));
@@ -568,8 +590,9 @@ public void createSplitsDir(RegionInfo daughterA, RegionInfo daughterB) throws I
568590
* have a reference to a Region.
569591
* @return Path to created reference.
570592
*/
571-
public Path splitStoreFile(RegionInfo hri, String familyName, HStoreFile f, byte[] splitRow,
572-
boolean top, RegionSplitPolicy splitPolicy, StoreFileTracker tracker) throws IOException {
593+
public StoreFileInfo splitStoreFile(RegionInfo hri, String familyName, HStoreFile f,
594+
byte[] splitRow, boolean top, RegionSplitPolicy splitPolicy, StoreFileTracker tracker)
595+
throws IOException {
573596
Path splitDir = new Path(getSplitsDir(hri), familyName);
574597
// Add the referred-to regions name as a dot separated suffix.
575598
// See REF_NAME_REGEX regex above. The referred-to regions name is
@@ -581,7 +604,7 @@ public Path splitStoreFile(RegionInfo hri, String familyName, HStoreFile f, byte
581604
Path p = new Path(splitDir, f.getPath().getName() + "." + parentRegionName);
582605
if (fs.exists(p)) {
583606
LOG.warn("Found an already existing split file for {}. Assuming this is a recovery.", p);
584-
return p;
607+
return tracker.getStoreFileInfo(fs.getFileStatus(p), p, true);
585608
}
586609
boolean createLinkFile = false;
587610
if (splitPolicy == null || !splitPolicy.skipStoreFileRangeCheck(familyName)) {
@@ -639,12 +662,12 @@ public Path splitStoreFile(RegionInfo hri, String familyName, HStoreFile f, byte
639662
hfileName = m.group(4);
640663
}
641664
// must create back reference here
642-
tracker.createHFileLink(linkedTable, linkedRegion, hfileName, true);
665+
HFileLink hFileLink = tracker.createHFileLink(linkedTable, linkedRegion, hfileName, true);
643666
Path path =
644667
new Path(splitDir, HFileLink.createHFileLinkName(linkedTable, linkedRegion, hfileName));
645668
LOG.info("Created linkFile:" + path.toString() + " for child: " + hri.getEncodedName()
646669
+ ", parent: " + regionInfoForFs.getEncodedName());
647-
return path;
670+
return new StoreFileInfo(conf, fs, path, hFileLink);
648671
} catch (IOException e) {
649672
// if create HFileLink file failed, then just skip the error and create Reference file
650673
LOG.error("Create link file for " + hfileName + " for child " + hri.getEncodedName()
@@ -655,7 +678,7 @@ public Path splitStoreFile(RegionInfo hri, String familyName, HStoreFile f, byte
655678
Reference r =
656679
top ? Reference.createTopReference(splitRow) : Reference.createBottomReference(splitRow);
657680
tracker.createReference(r, p);
658-
return p;
681+
return new StoreFileInfo(conf, fs, p, r);
659682
}
660683

661684
// ===========================================================================
@@ -696,7 +719,7 @@ static boolean mkdirs(FileSystem fs, Configuration conf, Path dir) throws IOExce
696719
* @return Path to created reference.
697720
* @throws IOException if the merge write fails.
698721
*/
699-
public Path mergeStoreFile(RegionInfo mergingRegion, String familyName, HStoreFile f,
722+
public StoreFileInfo mergeStoreFile(RegionInfo mergingRegion, String familyName, HStoreFile f,
700723
StoreFileTracker tracker) throws IOException {
701724
Path referenceDir = new Path(getMergesDir(regionInfoForFs), familyName);
702725
// A whole reference to the store file.
@@ -710,21 +733,22 @@ public Path mergeStoreFile(RegionInfo mergingRegion, String familyName, HStoreFi
710733
// suffix and into the new region location (under same family).
711734
Path p = new Path(referenceDir, f.getPath().getName() + "." + mergingRegionName);
712735
tracker.createReference(r, p);
713-
return p;
736+
StoreFileInfo storeFileInfo = new StoreFileInfo(conf, fs, p, r);
737+
return storeFileInfo;
714738
}
715739

716740
/**
717741
* Commit a merged region, making it ready for use.
718742
*/
719-
public void commitMergedRegion(List<Path> allMergedFiles, MasterProcedureEnv env)
743+
public void commitMergedRegion(List<StoreFileInfo> allMergedFiles, MasterProcedureEnv env)
720744
throws IOException {
721745
Path regionDir = getMergesDir(regionInfoForFs);
722746
if (regionDir != null && fs.exists(regionDir)) {
723747
// Write HRI to a file in case we need to recover hbase:meta
724748
Path regionInfoFile = new Path(regionDir, REGION_INFO_FILE);
725749
byte[] regionInfoContent = getRegionInfoFileContent(regionInfo);
726750
writeRegionInfoFileContent(conf, fs, regionInfoFile, regionInfoContent);
727-
insertRegionFilesIntoStoreTracker(allMergedFiles, env, this);
751+
insertRegionfilePathsIntoStoreTracker(allMergedFiles, env, this);
728752
}
729753
}
730754

0 commit comments

Comments
 (0)