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.master.region;
019
020import static org.apache.hadoop.hbase.HConstants.HREGION_LOGDIR_NAME;
021
022import com.google.errorprone.annotations.RestrictedApi;
023import java.io.IOException;
024import java.util.List;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.fs.FileStatus;
027import org.apache.hadoop.fs.FileSystem;
028import org.apache.hadoop.fs.Path;
029import org.apache.hadoop.hbase.HBaseIOException;
030import org.apache.hadoop.hbase.RegionTooBusyException;
031import org.apache.hadoop.hbase.Server;
032import org.apache.hadoop.hbase.TableName;
033import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
034import org.apache.hadoop.hbase.client.ConnectionUtils;
035import org.apache.hadoop.hbase.client.Get;
036import org.apache.hadoop.hbase.client.RegionInfo;
037import org.apache.hadoop.hbase.client.RegionInfoBuilder;
038import org.apache.hadoop.hbase.client.Result;
039import org.apache.hadoop.hbase.client.ResultScanner;
040import org.apache.hadoop.hbase.client.Scan;
041import org.apache.hadoop.hbase.client.TableDescriptor;
042import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
043import org.apache.hadoop.hbase.log.HBaseMarkers;
044import org.apache.hadoop.hbase.regionserver.HRegion;
045import org.apache.hadoop.hbase.regionserver.HRegion.FlushResult;
046import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
047import org.apache.hadoop.hbase.regionserver.RegionScanner;
048import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
049import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTracker;
050import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory;
051import org.apache.hadoop.hbase.regionserver.wal.AbstractFSWAL;
052import org.apache.hadoop.hbase.regionserver.wal.WALSyncTimeoutIOException;
053import org.apache.hadoop.hbase.util.Bytes;
054import org.apache.hadoop.hbase.util.CommonFSUtils;
055import org.apache.hadoop.hbase.util.FSTableDescriptors;
056import org.apache.hadoop.hbase.util.FSUtils;
057import org.apache.hadoop.hbase.util.HFileArchiveUtil;
058import org.apache.hadoop.hbase.util.RecoverLeaseFSUtils;
059import org.apache.hadoop.hbase.util.Threads;
060import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
061import org.apache.hadoop.hbase.wal.WAL;
062import org.apache.hadoop.hbase.wal.WALFactory;
063import org.apache.yetus.audience.InterfaceAudience;
064import org.slf4j.Logger;
065import org.slf4j.LoggerFactory;
066
067import org.apache.hbase.thirdparty.com.google.common.math.IntMath;
068
069/**
070 * A region that stores data in a separated directory, which can be used to store master local data.
071 * <p/>
072 * FileSystem layout:
073 *
074 * <pre>
075 * hbase
076 *   |
077 *   --&lt;region dir&gt;
078 *       |
079 *       --data
080 *       |  |
081 *       |  --/&lt;ns&gt/&lt;table&gt/&lt;encoded-region-name&gt; <---- The region data
082 *       |      |
083 *       |      --replay <---- The edits to replay
084 *       |
085 *       --WALs
086 *          |
087 *          --&lt;master-server-name&gt; <---- The WAL dir for active master
088 *          |
089 *          --&lt;master-server-name&gt;-dead <---- The WAL dir for dead master
090 * </pre>
091 *
092 * Notice that, you can use different root file system and WAL file system. Then the above directory
093 * will be on two file systems, the root file system will have the data directory while the WAL
094 * filesystem will have the WALs directory. The archived HFile will be moved to the global HFile
095 * archived directory with the {@link MasterRegionParams#archivedHFileSuffix()} suffix. The archived
096 * WAL will be moved to the global WAL archived directory with the
097 * {@link MasterRegionParams#archivedWalSuffix()} suffix.
098 */
099@InterfaceAudience.Private
100public final class MasterRegion {
101
102  private static final Logger LOG = LoggerFactory.getLogger(MasterRegion.class);
103
104  private static final String REPLAY_EDITS_DIR = "recovered.wals";
105
106  private static final String DEAD_WAL_DIR_SUFFIX = "-dead";
107
108  static final String INITIALIZING_FLAG = ".initializing";
109
110  static final String INITIALIZED_FLAG = ".initialized";
111
112  private static final int REGION_ID = 1;
113
114  private final Server server;
115
116  private final WALFactory walFactory;
117
118  final HRegion region;
119
120  final MasterRegionFlusherAndCompactor flusherAndCompactor;
121
122  private MasterRegionWALRoller walRoller;
123
124  private final int maxRetriesForRegionUpdates;
125
126  private final long regionUpdateRetryPauseTime;
127
128  private MasterRegion(Server server, HRegion region, WALFactory walFactory,
129    MasterRegionFlusherAndCompactor flusherAndCompactor, MasterRegionWALRoller walRoller) {
130    this.server = server;
131    this.region = region;
132    this.walFactory = walFactory;
133    this.flusherAndCompactor = flusherAndCompactor;
134    this.walRoller = walRoller;
135    this.maxRetriesForRegionUpdates =
136      server.getConfiguration().getInt("hbase.master.region.update.max.retries", 9);
137    this.regionUpdateRetryPauseTime =
138      server.getConfiguration().getLong("hbase.master.region.update.retry.pause", 100);
139  }
140
141  private void closeRegion(boolean abort) {
142    try {
143      region.close(abort);
144    } catch (IOException e) {
145      LOG.warn("Failed to close region", e);
146    }
147  }
148
149  private void shutdownWAL() {
150    try {
151      walFactory.shutdown();
152    } catch (IOException e) {
153      LOG.warn("Failed to shutdown WAL", e);
154    }
155  }
156
157  /**
158   * Performs the mutation to the master region using UpdateMasterRegion update action.
159   * @param action Update region action.
160   * @throws IOException IO error that causes active master to abort.
161   */
162  public void update(UpdateMasterRegion action) throws IOException {
163    for (int tries = 0; tries < maxRetriesForRegionUpdates; tries++) {
164      try {
165        // If the update is successful, return immediately.
166        action.update(region);
167        flusherAndCompactor.onUpdate();
168        return;
169      } catch (RegionTooBusyException e) {
170        // RegionTooBusyException is the type of IOException for which we can retry
171        // for few times before aborting the active master. The master region might
172        // have genuine case for delayed flushes and/or some procedure bug causing
173        // heavy pressure on the memstore.
174        flusherAndCompactor.onUpdate();
175        if (tries == (maxRetriesForRegionUpdates - 1)) {
176          abortServer(e);
177        }
178        LOG.info("Master region {} is too busy... retry attempt: {}", region, tries);
179        // Exponential backoff is performed by ConnectionUtils.getPauseTime().
180        // It uses HConstants.RETRY_BACKOFF array for the backoff multiplier, the
181        // same array is used as backoff multiplier with RPC retries.
182        Threads.sleep(ConnectionUtils.getPauseTime(regionUpdateRetryPauseTime, tries));
183      } catch (IOException e) {
184        // We catch IOException here to ensure that if the mutation is not successful
185        // even after the internal retries done within AbstractFSWAL, we better abort
186        // the active master so that the new active master can take care of resuming
187        // the procedure state which could not be persisted successfully by previously
188        // aborted master. Refer to Jira: HBASE-29251.
189        abortServer(e);
190      }
191    }
192  }
193
194  /**
195   * Log the error and abort the master daemon immediately. Use this utility only when procedure
196   * state store update fails and the only way to recover is by terminating the active master so
197   * that new failed-over active master can resume the procedure execution.
198   * @param e IO error that causes active master to abort.
199   * @throws IOException IO error that causes active master to abort.
200   */
201  private void abortServer(IOException e) throws IOException {
202    LOG.error(HBaseMarkers.FATAL,
203      "MasterRegion update is not successful. Aborting server to let new active master "
204        + "resume failed proc store update.");
205    server.abort("MasterRegion update is not successful", e);
206    throw e;
207  }
208
209  public Result get(Get get) throws IOException {
210    return region.get(get);
211  }
212
213  public ResultScanner getScanner(Scan scan) throws IOException {
214    return new RegionScannerAsResultScanner(region.getScanner(scan));
215  }
216
217  public RegionScanner getRegionScanner(Scan scan) throws IOException {
218    return region.getScanner(scan);
219  }
220
221  public FlushResult flush(boolean force) throws IOException {
222    try {
223      flusherAndCompactor.resetChangesAfterLastFlush();
224      FlushResult flushResult = region.flush(force);
225      flusherAndCompactor.recordLastFlushTime();
226      return flushResult;
227    } catch (WALSyncTimeoutIOException e) {
228      LOG.error(HBaseMarkers.FATAL, "WAL sync timeout. Aborting server.");
229      server.abort("WAL sync timeout", e);
230      throw e;
231    }
232  }
233
234  @RestrictedApi(explanation = "Should only be called in tests", link = "",
235      allowedOnPath = ".*/src/test/.*")
236  public void requestRollAll() {
237    walRoller.requestRollAll();
238  }
239
240  @RestrictedApi(explanation = "Should only be called in tests", link = "",
241      allowedOnPath = ".*/src/test/.*")
242  public void waitUntilWalRollFinished() throws InterruptedException {
243    walRoller.waitUntilWalRollFinished();
244  }
245
246  public void close(boolean abort) {
247    LOG.info("Closing local region {}, isAbort={}", region.getRegionInfo(), abort);
248    if (flusherAndCompactor != null) {
249      flusherAndCompactor.close();
250    }
251    // if abort, we shutdown wal first to fail the ongoing updates to the region, and then close the
252    // region, otherwise there will be dead lock.
253    if (abort) {
254      shutdownWAL();
255      closeRegion(true);
256    } else {
257      closeRegion(false);
258      shutdownWAL();
259    }
260
261    if (walRoller != null) {
262      walRoller.close();
263    }
264  }
265
266  private static WAL createWAL(WALFactory walFactory, MasterRegionWALRoller walRoller,
267    String serverName, FileSystem walFs, Path walRootDir, RegionInfo regionInfo)
268    throws IOException {
269    String logName = AbstractFSWALProvider.getWALDirectoryName(serverName);
270    Path walDir = new Path(walRootDir, logName);
271    LOG.debug("WALDir={}", walDir);
272    if (walFs.exists(walDir)) {
273      throw new HBaseIOException(
274        "Already created wal directory at " + walDir + " for local region " + regionInfo);
275    }
276    if (!walFs.mkdirs(walDir)) {
277      throw new IOException(
278        "Can not create wal directory " + walDir + " for local region " + regionInfo);
279    }
280    WAL wal = walFactory.getWAL(regionInfo);
281    walRoller.addWAL(wal);
282    return wal;
283  }
284
285  private static HRegion bootstrap(Configuration conf, TableDescriptor td, FileSystem fs,
286    Path rootDir, FileSystem walFs, Path walRootDir, WALFactory walFactory,
287    MasterRegionWALRoller walRoller, String serverName, boolean touchInitializingFlag)
288    throws IOException {
289    TableName tn = td.getTableName();
290    RegionInfo regionInfo = RegionInfoBuilder.newBuilder(tn).setRegionId(REGION_ID).build();
291    Path tableDir = CommonFSUtils.getTableDir(rootDir, tn);
292    // persist table descriptor
293    FSTableDescriptors.createTableDescriptorForTableDirectory(fs, tableDir, td, true);
294    HRegion.createHRegion(conf, regionInfo, fs, tableDir, td).close();
295    Path initializedFlag = new Path(tableDir, INITIALIZED_FLAG);
296    if (!fs.mkdirs(initializedFlag)) {
297      throw new IOException("Can not touch initialized flag: " + initializedFlag);
298    }
299    Path initializingFlag = new Path(tableDir, INITIALIZING_FLAG);
300    if (!fs.delete(initializingFlag, true)) {
301      LOG.warn("failed to clean up initializing flag: " + initializingFlag);
302    }
303    WAL wal = createWAL(walFactory, walRoller, serverName, walFs, walRootDir, regionInfo);
304    return HRegion.openHRegionFromTableDir(conf, fs, tableDir, regionInfo, td, wal, null, null);
305  }
306
307  private static RegionInfo loadRegionInfo(FileSystem fs, Path tableDir) throws IOException {
308    Path regionDir =
309      fs.listStatus(tableDir, p -> RegionInfo.isEncodedRegionName(Bytes.toBytes(p.getName())))[0]
310        .getPath();
311    return HRegionFileSystem.loadRegionInfoFileContent(fs, regionDir);
312  }
313
314  private static HRegion open(Configuration conf, TableDescriptor td, RegionInfo regionInfo,
315    FileSystem fs, Path rootDir, FileSystem walFs, Path walRootDir, WALFactory walFactory,
316    MasterRegionWALRoller walRoller, String serverName) throws IOException {
317    Path tableDir = CommonFSUtils.getTableDir(rootDir, td.getTableName());
318    Path walRegionDir = FSUtils.getRegionDirFromRootDir(walRootDir, regionInfo);
319    Path replayEditsDir = new Path(walRegionDir, REPLAY_EDITS_DIR);
320    if (!walFs.exists(replayEditsDir) && !walFs.mkdirs(replayEditsDir)) {
321      throw new IOException("Failed to create replay directory: " + replayEditsDir);
322    }
323
324    // Replay any WALs for the Master Region before opening it.
325    Path walsDir = new Path(walRootDir, HREGION_LOGDIR_NAME);
326    // In open(...), we expect that the WAL directory for the MasterRegion to already exist.
327    // This is in contrast to bootstrap() where we create the MasterRegion data and WAL dir.
328    // However, it's possible that users directly remove the WAL directory. We expect walsDir
329    // to always exist in normal situations, but we should guard against users changing the
330    // filesystem outside of HBase's line of sight.
331    if (walFs.exists(walsDir)) {
332      replayWALs(conf, walFs, walRootDir, walsDir, regionInfo, serverName, replayEditsDir);
333    } else {
334      LOG.error(
335        "UNEXPECTED: WAL directory for MasterRegion is missing." + " {} is unexpectedly missing.",
336        walsDir);
337    }
338
339    // Create a new WAL
340    WAL wal = createWAL(walFactory, walRoller, serverName, walFs, walRootDir, regionInfo);
341    conf.set(HRegion.SPECIAL_RECOVERED_EDITS_DIR,
342      replayEditsDir.makeQualified(walFs.getUri(), walFs.getWorkingDirectory()).toString());
343    // we do not do WAL splitting here so it is possible to have uncleanly closed WAL files, so we
344    // need to ignore EOFException.
345    conf.setBoolean(HRegion.RECOVERED_EDITS_IGNORE_EOF, true);
346    return HRegion.openHRegionFromTableDir(conf, fs, tableDir, regionInfo, td, wal, null, null);
347  }
348
349  private static void replayWALs(Configuration conf, FileSystem walFs, Path walRootDir,
350    Path walsDir, RegionInfo regionInfo, String serverName, Path replayEditsDir)
351    throws IOException {
352    for (FileStatus walDir : walFs.listStatus(walsDir)) {
353      if (!walDir.isDirectory()) {
354        continue;
355      }
356      if (walDir.getPath().getName().startsWith(serverName)) {
357        LOG.warn("This should not happen in real production as we have not created our WAL "
358          + "directory yet, ignore if you are running a local region related UT");
359      }
360      Path deadWALDir;
361      if (!walDir.getPath().getName().endsWith(DEAD_WAL_DIR_SUFFIX)) {
362        deadWALDir =
363          new Path(walDir.getPath().getParent(), walDir.getPath().getName() + DEAD_WAL_DIR_SUFFIX);
364        if (!walFs.rename(walDir.getPath(), deadWALDir)) {
365          throw new IOException("Can not rename " + walDir + " to " + deadWALDir
366            + " when recovering lease of proc store");
367        }
368        LOG.info("Renamed {} to {} as it is dead", walDir.getPath(), deadWALDir);
369      } else {
370        deadWALDir = walDir.getPath();
371        LOG.info("{} is already marked as dead", deadWALDir);
372      }
373      for (FileStatus walFile : walFs.listStatus(deadWALDir)) {
374        Path replayEditsFile = new Path(replayEditsDir, walFile.getPath().getName());
375        RecoverLeaseFSUtils.recoverFileLease(walFs, walFile.getPath(), conf);
376        if (!walFs.rename(walFile.getPath(), replayEditsFile)) {
377          throw new IOException("Can not rename " + walFile.getPath() + " to " + replayEditsFile
378            + " when recovering lease for local region");
379        }
380        LOG.info("Renamed {} to {}", walFile.getPath(), replayEditsFile);
381      }
382      LOG.info("Delete empty local region wal dir {}", deadWALDir);
383      walFs.delete(deadWALDir, true);
384    }
385  }
386
387  private static void tryMigrate(Configuration conf, FileSystem fs, Path tableDir,
388    RegionInfo regionInfo, TableDescriptor oldTd, TableDescriptor newTd) throws IOException {
389    Class<? extends StoreFileTracker> oldSft =
390      StoreFileTrackerFactory.getTrackerClass(oldTd.getValue(StoreFileTrackerFactory.TRACKER_IMPL));
391    Class<? extends StoreFileTracker> newSft =
392      StoreFileTrackerFactory.getTrackerClass(newTd.getValue(StoreFileTrackerFactory.TRACKER_IMPL));
393    if (oldSft.equals(newSft)) {
394      LOG.debug("old store file tracker {} is the same with new store file tracker, skip migration",
395        StoreFileTrackerFactory.getStoreFileTrackerName(oldSft));
396      if (!oldTd.equals(newTd)) {
397        // we may change other things such as adding a new family, so here we still need to persist
398        // the new table descriptor
399        LOG.info("Update table descriptor from {} to {}", oldTd, newTd);
400        FSTableDescriptors.createTableDescriptorForTableDirectory(fs, tableDir, newTd, true);
401      }
402      return;
403    }
404    LOG.info("Migrate store file tracker from {} to {}", oldSft.getSimpleName(),
405      newSft.getSimpleName());
406    HRegionFileSystem hfs =
407      HRegionFileSystem.openRegionFromFileSystem(conf, fs, tableDir, regionInfo, false);
408    for (ColumnFamilyDescriptor oldCfd : oldTd.getColumnFamilies()) {
409      StoreFileTracker oldTracker = StoreFileTrackerFactory.create(conf, oldTd, oldCfd, hfs);
410      StoreFileTracker newTracker = StoreFileTrackerFactory.create(conf, oldTd, oldCfd, hfs);
411      List<StoreFileInfo> files = oldTracker.load();
412      LOG.debug("Store file list for {}: {}", oldCfd.getNameAsString(), files);
413      newTracker.set(oldTracker.load());
414    }
415    // persist the new table descriptor after migration
416    LOG.info("Update table descriptor from {} to {}", oldTd, newTd);
417    FSTableDescriptors.createTableDescriptorForTableDirectory(fs, tableDir, newTd, true);
418  }
419
420  public static MasterRegion create(MasterRegionParams params) throws IOException {
421    TableDescriptor td = params.tableDescriptor();
422    LOG.info("Create or load local region for table " + td);
423    Server server = params.server();
424    Configuration baseConf = server.getConfiguration();
425    FileSystem fs = CommonFSUtils.getRootDirFileSystem(baseConf);
426    FileSystem walFs = CommonFSUtils.getWALFileSystem(baseConf);
427    Path globalRootDir = CommonFSUtils.getRootDir(baseConf);
428    Path globalWALRootDir = CommonFSUtils.getWALRootDir(baseConf);
429    Path rootDir = new Path(globalRootDir, params.regionDirName());
430    Path walRootDir = new Path(globalWALRootDir, params.regionDirName());
431    // we will override some configurations so create a new one.
432    Configuration conf = new Configuration(baseConf);
433    CommonFSUtils.setRootDir(conf, rootDir);
434    CommonFSUtils.setWALRootDir(conf, walRootDir);
435    MasterRegionFlusherAndCompactor.setupConf(conf, params.flushSize(), params.flushPerChanges(),
436      params.flushIntervalMs());
437    conf.setInt(AbstractFSWAL.MAX_LOGS, params.maxWals());
438    if (params.useHsync() != null) {
439      conf.setBoolean(HRegion.WAL_HSYNC_CONF_KEY, params.useHsync());
440    }
441    if (params.useMetaCellComparator() != null) {
442      conf.setBoolean(HRegion.USE_META_CELL_COMPARATOR, params.useMetaCellComparator());
443    }
444    conf.setInt(AbstractFSWAL.RING_BUFFER_SLOT_COUNT,
445      IntMath.ceilingPowerOfTwo(params.ringBufferSlotCount()));
446
447    MasterRegionWALRoller walRoller = MasterRegionWALRoller.create(
448      td.getTableName() + "-WAL-Roller", conf, server, walFs, walRootDir, globalWALRootDir,
449      params.archivedWalSuffix(), params.rollPeriodMs(), params.flushSize());
450    walRoller.start();
451
452    WALFactory walFactory = new WALFactory(conf, server.getServerName(), server);
453    Path tableDir = CommonFSUtils.getTableDir(rootDir, td.getTableName());
454    Path initializingFlag = new Path(tableDir, INITIALIZING_FLAG);
455    Path initializedFlag = new Path(tableDir, INITIALIZED_FLAG);
456    HRegion region;
457    if (!fs.exists(tableDir)) {
458      // bootstrap, no doubt
459      if (!fs.mkdirs(initializedFlag)) {
460        throw new IOException("Can not touch initialized flag");
461      }
462      region = bootstrap(conf, td, fs, rootDir, walFs, walRootDir, walFactory, walRoller,
463        server.getServerName().toString(), true);
464    } else {
465      if (!fs.exists(initializedFlag)) {
466        if (!fs.exists(initializingFlag)) {
467          // should be old style, where we do not have the initializing or initialized file, persist
468          // the table descriptor, touch the initialized flag and then open the region.
469          // the store file tracker must be DEFAULT
470          LOG.info("No {} or {} file, try upgrading", INITIALIZING_FLAG, INITIALIZED_FLAG);
471          TableDescriptor oldTd =
472            TableDescriptorBuilder.newBuilder(td).setValue(StoreFileTrackerFactory.TRACKER_IMPL,
473              StoreFileTrackerFactory.Trackers.DEFAULT.name()).build();
474          FSTableDescriptors.createTableDescriptorForTableDirectory(fs, tableDir, oldTd, true);
475          if (!fs.mkdirs(initializedFlag)) {
476            throw new IOException("Can not touch initialized flag: " + initializedFlag);
477          }
478          RegionInfo regionInfo = loadRegionInfo(fs, tableDir);
479          tryMigrate(conf, fs, tableDir, regionInfo, oldTd, td);
480          region = open(conf, td, regionInfo, fs, rootDir, walFs, walRootDir, walFactory, walRoller,
481            server.getServerName().toString());
482        } else {
483          // delete all contents besides the initializing flag, here we can make sure tableDir
484          // exists(unless someone delete it manually...), so we do not do null check here.
485          for (FileStatus status : fs.listStatus(tableDir)) {
486            if (!status.getPath().getName().equals(INITIALIZING_FLAG)) {
487              fs.delete(status.getPath(), true);
488            }
489          }
490          region = bootstrap(conf, td, fs, rootDir, walFs, walRootDir, walFactory, walRoller,
491            server.getServerName().toString(), false);
492        }
493      } else {
494        if (fs.exists(initializingFlag) && !fs.delete(initializingFlag, true)) {
495          LOG.warn("failed to clean up initializing flag: " + initializingFlag);
496        }
497        // open it, make sure to load the table descriptor from fs
498        TableDescriptor oldTd = FSTableDescriptors.getTableDescriptorFromFs(fs, tableDir);
499        RegionInfo regionInfo = loadRegionInfo(fs, tableDir);
500        tryMigrate(conf, fs, tableDir, regionInfo, oldTd, td);
501        region = open(conf, td, regionInfo, fs, rootDir, walFs, walRootDir, walFactory, walRoller,
502          server.getServerName().toString());
503      }
504    }
505
506    Path globalArchiveDir = HFileArchiveUtil.getArchivePath(baseConf);
507    MasterRegionFlusherAndCompactor flusherAndCompactor = new MasterRegionFlusherAndCompactor(conf,
508      server, region, params.flushSize(), params.flushPerChanges(), params.flushIntervalMs(),
509      params.compactMin(), globalArchiveDir, params.archivedHFileSuffix());
510    walRoller.setFlusherAndCompactor(flusherAndCompactor);
511    Path archiveDir = HFileArchiveUtil.getArchivePath(conf);
512    if (!fs.mkdirs(archiveDir)) {
513      LOG.warn("Failed to create archive directory {}. Usually this should not happen but it will"
514        + " be created again when we actually archive the hfiles later, so continue", archiveDir);
515    }
516    return new MasterRegion(server, region, walFactory, flusherAndCompactor, walRoller);
517  }
518}