Skip to content

Commit e441e19

Browse files
committed
HBASE-26187 Write straight into the store directory when Splitting an… (apache#3574)
Signed-off-by: Duo Zhang <[email protected]> Change-Id: I738cfe24ac599a01c76a8c2ee29bb94bd021151d
1 parent 8c84c31 commit e441e19

5 files changed

Lines changed: 310 additions & 167 deletions

File tree

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

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -583,34 +583,29 @@ private void setRegionStateToMerging(final MasterProcedureEnv env) {
583583
*/
584584
private void createMergedRegion(final MasterProcedureEnv env) throws IOException {
585585
final MasterFileSystem mfs = env.getMasterServices().getMasterFileSystem();
586-
final Path tabledir = CommonFSUtils.getTableDir(mfs.getRootDir(), regionsToMerge[0].getTable());
586+
final Path tableDir = CommonFSUtils.getTableDir(mfs.getRootDir(), regionsToMerge[0].getTable());
587587
final FileSystem fs = mfs.getFileSystem();
588-
HRegionFileSystem mergeRegionFs = null;
588+
589+
HRegionFileSystem mergeRegionFs = HRegionFileSystem.createRegionOnFileSystem(
590+
env.getMasterConfiguration(), fs, tableDir, mergedRegion);
591+
589592
for (RegionInfo ri: this.regionsToMerge) {
590593
HRegionFileSystem regionFs = HRegionFileSystem.openRegionFromFileSystem(
591-
env.getMasterConfiguration(), fs, tabledir, ri, false);
592-
if (mergeRegionFs == null) {
593-
mergeRegionFs = regionFs;
594-
mergeRegionFs.createMergesDir();
595-
}
596-
mergeStoreFiles(env, regionFs, mergeRegionFs.getMergesDir());
594+
env.getMasterConfiguration(), fs, tableDir, ri, false);
595+
mergeStoreFiles(env, regionFs, mergeRegionFs, mergedRegion);
597596
}
598597
assert mergeRegionFs != null;
599-
mergeRegionFs.commitMergedRegion(mergedRegion);
598+
mergeRegionFs.commitMergedRegion();
600599

601600
// Prepare to create merged regions
602601
env.getAssignmentManager().getRegionStates().
603602
getOrCreateRegionStateNode(mergedRegion).setState(State.MERGING_NEW);
604603
}
605604

606-
/**
607-
* Create reference file(s) to parent region hfiles in the <code>mergeDir</code>
608-
* @param regionFs merge parent region file system
609-
* @param mergeDir the temp directory in which we are accumulating references.
610-
*/
611-
private void mergeStoreFiles(final MasterProcedureEnv env, final HRegionFileSystem regionFs,
612-
final Path mergeDir) throws IOException {
613-
final TableDescriptor htd = env.getMasterServices().getTableDescriptors().get(getTableName());
605+
private void mergeStoreFiles(MasterProcedureEnv env, HRegionFileSystem regionFs,
606+
HRegionFileSystem mergeRegionFs, RegionInfo mergedRegion) throws IOException {
607+
final TableDescriptor htd = env.getMasterServices().getTableDescriptors()
608+
.get(mergedRegion.getTable());
614609
for (ColumnFamilyDescriptor hcd : htd.getColumnFamilies()) {
615610
String family = hcd.getNameAsString();
616611
final Collection<StoreFileInfo> storeFiles = regionFs.getStoreFiles(family);
@@ -619,8 +614,12 @@ private void mergeStoreFiles(final MasterProcedureEnv env, final HRegionFileSyst
619614
// Create reference file(s) to parent region file here in mergedDir.
620615
// As this procedure is running on master, use CacheConfig.DISABLED means
621616
// don't cache any block.
622-
regionFs.mergeStoreFile(mergedRegion, family, new HStoreFile(
623-
storeFileInfo, hcd.getBloomFilterType(), CacheConfig.DISABLED), mergeDir);
617+
mergeRegionFs.mergeStoreFile(regionFs.getRegionInfo(), family,
618+
new HStoreFile(mergeRegionFs.getFileSystem(),
619+
storeFileInfo.getPath(),
620+
env.getMasterConfiguration(),
621+
CacheConfig.DISABLED,
622+
hcd.getBloomFilterType(), true));
624623
}
625624
}
626625
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ protected void rollbackState(final MasterProcedureEnv env, final SplitTableRegio
374374
break;
375375
case SPLIT_TABLE_REGION_CREATE_DAUGHTER_REGIONS:
376376
case SPLIT_TABLE_REGION_WRITE_MAX_SEQUENCE_ID_FILE:
377-
// Doing nothing, as re-open parent region would clean up daughter region directories.
377+
deleteDaughterRegions(env);
378378
break;
379379
case SPLIT_TABLE_REGIONS_CHECK_CLOSED_REGIONS:
380380
// Doing nothing, in SPLIT_TABLE_REGION_CLOSE_PARENT_REGION,
@@ -638,6 +638,15 @@ public void createDaughterRegions(final MasterProcedureEnv env) throws IOExcepti
638638
new Path(tabledir, daughterTwoRI.getEncodedName()));
639639
}
640640

641+
private void deleteDaughterRegions(final MasterProcedureEnv env) throws IOException {
642+
final MasterFileSystem mfs = env.getMasterServices().getMasterFileSystem();
643+
final Path tabledir = CommonFSUtils.getTableDir(mfs.getRootDir(), getTableName());
644+
HRegionFileSystem.deleteRegionFromFileSystem(env.getMasterConfiguration(),
645+
mfs.getFileSystem(), tabledir, daughterOneRI);
646+
HRegionFileSystem.deleteRegionFromFileSystem(env.getMasterConfiguration(),
647+
mfs.getFileSystem(), tabledir, daughterTwoRI);
648+
}
649+
641650
/**
642651
* Create Split directory
643652
* @param env MasterProcedureEnv
@@ -650,9 +659,9 @@ private Pair<Integer, Integer> splitStoreFiles(final MasterProcedureEnv env,
650659
// there's files to split. It then fires up everything, waits for
651660
// completion and finally checks for any exception
652661
//
653-
// Note: splitStoreFiles creates daughter region dirs under the parent splits dir
654-
// Nothing to unroll here if failure -- re-run createSplitsDir will
655-
// clean this up.
662+
// Note: From HBASE-26187, splitStoreFiles now creates daughter region dirs straight under the
663+
// table dir. In case of failure, the proc would go through this again, already existing
664+
// region dirs and split files would just be ignored, new split files should get created.
656665
int nbFiles = 0;
657666
final Map<String, Collection<StoreFileInfo>> files =
658667
new HashMap<String, Collection<StoreFileInfo>>(htd.getColumnFamilyCount());

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,15 +1054,6 @@ private long initializeRegionInternals(final CancelableProgressable reporter,
10541054
fs.cleanupTempDir();
10551055
}
10561056

1057-
if (this.writestate.writesEnabled) {
1058-
status.setStatus("Cleaning up detritus from prior splits");
1059-
// Get rid of any splits or merges that were lost in-progress. Clean out
1060-
// these directories here on open. We may be opening a region that was
1061-
// being split but we crashed in the middle of it all.
1062-
fs.cleanupAnySplitDetritus();
1063-
fs.cleanupMergesDir();
1064-
}
1065-
10661057
// Initialize split policy
10671058
this.splitPolicy = RegionSplitPolicy.create(this, conf);
10681059

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

Lines changed: 46 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -575,49 +575,9 @@ Pair<Path, Path> bulkLoadStoreFile(final String familyName, Path srcPath, long s
575575
// ===========================================================================
576576
// Splits Helpers
577577
// ===========================================================================
578-
/** @return {@link Path} to the temp directory used during split operations */
579-
Path getSplitsDir() {
580-
return new Path(getRegionDir(), REGION_SPLITS_DIR);
581-
}
582578

583579
public Path getSplitsDir(final RegionInfo hri) {
584-
return new Path(getSplitsDir(), hri.getEncodedName());
585-
}
586-
587-
/**
588-
* Clean up any split detritus that may have been left around from previous split attempts.
589-
*/
590-
void cleanupSplitsDir() throws IOException {
591-
deleteDir(getSplitsDir());
592-
}
593-
594-
/**
595-
* Clean up any split detritus that may have been left around from previous
596-
* split attempts.
597-
* Call this method on initial region deploy.
598-
* @throws IOException
599-
*/
600-
void cleanupAnySplitDetritus() throws IOException {
601-
Path splitdir = this.getSplitsDir();
602-
if (!fs.exists(splitdir)) return;
603-
// Look at the splitdir. It could have the encoded names of the daughter
604-
// regions we tried to make. See if the daughter regions actually got made
605-
// out under the tabledir. If here under splitdir still, then the split did
606-
// not complete. Try and do cleanup. This code WILL NOT catch the case
607-
// where we successfully created daughter a but regionserver crashed during
608-
// the creation of region b. In this case, there'll be an orphan daughter
609-
// dir in the filesystem. TOOD: Fix.
610-
FileStatus[] daughters = CommonFSUtils.listStatus(fs, splitdir, new FSUtils.DirFilter(fs));
611-
if (daughters != null) {
612-
for (FileStatus daughter: daughters) {
613-
Path daughterDir = new Path(getTableDir(), daughter.getPath().getName());
614-
if (fs.exists(daughterDir) && !deleteDir(daughterDir)) {
615-
throw new IOException("Failed delete of " + daughterDir);
616-
}
617-
}
618-
}
619-
cleanupSplitsDir();
620-
LOG.info("Cleaned up old failed split transaction detritus: " + splitdir);
580+
return new Path(getTableDir(), hri.getEncodedName());
621581
}
622582

623583
/**
@@ -641,47 +601,38 @@ void cleanupDaughterRegion(final RegionInfo regionInfo) throws IOException {
641601
*/
642602
public Path commitDaughterRegion(final RegionInfo regionInfo)
643603
throws IOException {
644-
Path regionDir = new Path(this.tableDir, regionInfo.getEncodedName());
645-
Path daughterTmpDir = this.getSplitsDir(regionInfo);
646-
647-
if (fs.exists(daughterTmpDir)) {
648-
604+
Path regionDir = this.getSplitsDir(regionInfo);
605+
if (fs.exists(regionDir)) {
649606
// Write HRI to a file in case we need to recover hbase:meta
650-
Path regionInfoFile = new Path(daughterTmpDir, REGION_INFO_FILE);
607+
Path regionInfoFile = new Path(regionDir, REGION_INFO_FILE);
651608
byte[] regionInfoContent = getRegionInfoFileContent(regionInfo);
652609
writeRegionInfoFileContent(conf, fs, regionInfoFile, regionInfoContent);
653-
654-
// Move the daughter temp dir to the table dir
655-
if (!rename(daughterTmpDir, regionDir)) {
656-
throw new IOException("Unable to rename " + daughterTmpDir + " to " + regionDir);
657-
}
658610
}
659611

660612
return regionDir;
661613
}
662614

663615
/**
664-
* Create the region splits directory.
616+
* Creates region split daughter directories under the table dir. If the daughter regions already
617+
* exist, for example, in the case of a recovery from a previous failed split procedure, this
618+
* method deletes the given region dir recursively, then recreates it again.
665619
*/
666620
public void createSplitsDir(RegionInfo daughterA, RegionInfo daughterB) throws IOException {
667-
Path splitdir = getSplitsDir();
668-
if (fs.exists(splitdir)) {
669-
LOG.info("The " + splitdir + " directory exists. Hence deleting it to recreate it");
670-
if (!deleteDir(splitdir)) {
671-
throw new IOException("Failed deletion of " + splitdir + " before creating them again.");
672-
}
621+
Path daughterADir = getSplitsDir(daughterA);
622+
if (fs.exists(daughterADir) && !deleteDir(daughterADir)) {
623+
throw new IOException("Failed deletion of " + daughterADir + " before creating them again.");
624+
673625
}
674-
// splitDir doesn't exists now. No need to do an exists() call for it.
675-
if (!createDir(splitdir)) {
676-
throw new IOException("Failed create of " + splitdir);
626+
if (!createDir(daughterADir)) {
627+
throw new IOException("Failed create of " + daughterADir);
677628
}
678-
Path daughterATmpDir = getSplitsDir(daughterA);
679-
if (!createDir(daughterATmpDir)) {
680-
throw new IOException("Failed create of " + daughterATmpDir);
629+
Path daughterBDir = getSplitsDir(daughterB);
630+
if (fs.exists(daughterBDir) && !deleteDir(daughterBDir)) {
631+
throw new IOException("Failed deletion of " + daughterBDir + " before creating them again.");
632+
681633
}
682-
Path daughterBTmpDir = getSplitsDir(daughterB);
683-
if (!createDir(daughterBTmpDir)) {
684-
throw new IOException("Failed create of " + daughterBTmpDir);
634+
if (!createDir(daughterBDir)) {
635+
throw new IOException("Failed create of " + daughterBDir);
685636
}
686637
}
687638

@@ -703,6 +654,18 @@ public Path splitStoreFile(RegionInfo hri, String familyName, HStoreFile f, byte
703654
boolean top, RegionSplitPolicy splitPolicy) throws IOException {
704655
boolean createLinkFile = false;
705656
Path splitDir = new Path(getSplitsDir(hri), familyName);
657+
// Add the referred-to regions name as a dot separated suffix.
658+
// See REF_NAME_REGEX regex above. The referred-to regions name is
659+
// up in the path of the passed in <code>f</code> -- parentdir is family,
660+
// then the directory above is the region name.
661+
String parentRegionName = regionInfoForFs.getEncodedName();
662+
// Write reference with same file id only with the other region name as
663+
// suffix and into the new region location (under same family).
664+
Path p = new Path(splitDir, f.getPath().getName() + "." + parentRegionName);
665+
if(fs.exists(p)){
666+
LOG.warn("Found an already existing split file for {}. Assuming this is a recovery.", p);
667+
return p;
668+
}
706669
if (splitPolicy == null || !splitPolicy.skipStoreFileRangeCheck(familyName)) {
707670
// Check whether the split row lies in the range of the store file
708671
// If it is outside the range, return directly.
@@ -775,35 +738,17 @@ public Path splitStoreFile(RegionInfo hri, String familyName, HStoreFile f, byte
775738
// A reference to the bottom half of the hsf store file.
776739
Reference r =
777740
top ? Reference.createTopReference(splitRow): Reference.createBottomReference(splitRow);
778-
// Add the referred-to regions name as a dot separated suffix.
779-
// See REF_NAME_REGEX regex above. The referred-to regions name is
780-
// up in the path of the passed in <code>f</code> -- parentdir is family,
781-
// then the directory above is the region name.
782-
String parentRegionName = regionInfoForFs.getEncodedName();
783-
// Write reference with same file id only with the other region name as
784-
// suffix and into the new region location (under same family).
785-
Path p = new Path(splitDir, f.getPath().getName() + "." + parentRegionName);
786741
return r.write(fs, p);
787742
}
788743

789744
// ===========================================================================
790745
// Merge Helpers
791746
// ===========================================================================
792-
/** @return {@link Path} to the temp directory used during merge operations */
793-
public Path getMergesDir() {
794-
return new Path(getRegionDir(), REGION_MERGES_DIR);
795-
}
796747

797748
Path getMergesDir(final RegionInfo hri) {
798-
return new Path(getMergesDir(), hri.getEncodedName());
749+
return new Path(getTableDir(), hri.getEncodedName());
799750
}
800751

801-
/**
802-
* Clean up any merge detritus that may have been left around from previous merge attempts.
803-
*/
804-
void cleanupMergesDir() throws IOException {
805-
deleteDir(getMergesDir());
806-
}
807752

808753
/**
809754
* Remove merged region
@@ -827,73 +772,41 @@ static boolean mkdirs(FileSystem fs, Configuration conf, Path dir) throws IOExce
827772
}
828773

829774
/**
830-
* Create the region merges directory, a temporary directory to accumulate
831-
* merges in.
832-
* @throws IOException If merges dir already exists or we fail to create it.
833-
* @see HRegionFileSystem#cleanupMergesDir()
834-
*/
835-
public void createMergesDir() throws IOException {
836-
Path mergesdir = getMergesDir();
837-
if (fs.exists(mergesdir)) {
838-
LOG.info("{} directory exists. Deleting it to recreate it anew", mergesdir);
839-
if (!fs.delete(mergesdir, true)) {
840-
throw new IOException("Failed deletion of " + mergesdir + " before recreate.");
841-
}
842-
}
843-
if (!mkdirs(fs, conf, mergesdir)) {
844-
throw new IOException("Failed create of " + mergesdir);
845-
}
846-
}
847-
848-
/**
849-
* Write out a merge reference under the given merges directory. Package local
850-
* so it doesnt leak out of regionserver.
851-
* @param mergedRegion {@link RegionInfo} of the merged region
775+
* Write out a merge reference under the given merges directory.
776+
* @param mergingRegion {@link RegionInfo} for one of the regions being merged.
852777
* @param familyName Column Family Name
853778
* @param f File to create reference.
854-
* @param mergedDir
855779
* @return Path to created reference.
856-
* @throws IOException
780+
* @throws IOException if the merge write fails.
857781
*/
858-
public Path mergeStoreFile(RegionInfo mergedRegion, String familyName, HStoreFile f,
859-
Path mergedDir) throws IOException {
860-
Path referenceDir = new Path(new Path(mergedDir,
861-
mergedRegion.getEncodedName()), familyName);
782+
public Path mergeStoreFile(RegionInfo mergingRegion, String familyName, HStoreFile f)
783+
throws IOException {
784+
Path referenceDir = new Path(getMergesDir(regionInfoForFs), familyName);
862785
// A whole reference to the store file.
863-
Reference r = Reference.createTopReference(regionInfoForFs.getStartKey());
786+
Reference r = Reference.createTopReference(mergingRegion.getStartKey());
864787
// Add the referred-to regions name as a dot separated suffix.
865788
// See REF_NAME_REGEX regex above. The referred-to regions name is
866789
// up in the path of the passed in <code>f</code> -- parentdir is family,
867790
// then the directory above is the region name.
868-
String mergingRegionName = regionInfoForFs.getEncodedName();
791+
String mergingRegionName = mergingRegion.getEncodedName();
869792
// Write reference with same file id only with the other region name as
870793
// suffix and into the new region location (under same family).
871794
Path p = new Path(referenceDir, f.getPath().getName() + "."
872-
+ mergingRegionName);
795+
+ mergingRegionName);
873796
return r.write(fs, p);
874797
}
875798

876799
/**
877-
* Commit a merged region, moving it from the merges temporary directory to
878-
* the proper location in the filesystem.
879-
* @param mergedRegionInfo merged region {@link RegionInfo}
800+
* Commit a merged region, making it ready for use.
880801
* @throws IOException
881802
*/
882-
public void commitMergedRegion(final RegionInfo mergedRegionInfo) throws IOException {
883-
Path regionDir = new Path(this.tableDir, mergedRegionInfo.getEncodedName());
884-
Path mergedRegionTmpDir = this.getMergesDir(mergedRegionInfo);
885-
// Move the tmp dir to the expected location
886-
if (mergedRegionTmpDir != null && fs.exists(mergedRegionTmpDir)) {
887-
803+
public void commitMergedRegion() throws IOException {
804+
Path regionDir = getMergesDir(regionInfoForFs);
805+
if (regionDir != null && fs.exists(regionDir)) {
888806
// Write HRI to a file in case we need to recover hbase:meta
889-
Path regionInfoFile = new Path(mergedRegionTmpDir, REGION_INFO_FILE);
807+
Path regionInfoFile = new Path(regionDir, REGION_INFO_FILE);
890808
byte[] regionInfoContent = getRegionInfoFileContent(regionInfo);
891809
writeRegionInfoFileContent(conf, fs, regionInfoFile, regionInfoContent);
892-
893-
if (!fs.rename(mergedRegionTmpDir, regionDir)) {
894-
throw new IOException("Unable to rename " + mergedRegionTmpDir + " to "
895-
+ regionDir);
896-
}
897810
}
898811
}
899812

@@ -1098,8 +1011,6 @@ public static HRegionFileSystem openRegionFromFileSystem(final Configuration con
10981011
if (!readOnly) {
10991012
// Cleanup temporary directories
11001013
regionFs.cleanupTempDir();
1101-
regionFs.cleanupSplitsDir();
1102-
regionFs.cleanupMergesDir();
11031014

11041015
// If it doesn't exists, Write HRI to a file, in case we need to recover hbase:meta
11051016
// Only create HRI if we are the default replica

0 commit comments

Comments
 (0)