|
20 | 20 | import static org.apache.hadoop.hbase.HConstants.HREGION_LOGDIR_NAME;
|
21 | 21 |
|
22 | 22 | import java.io.IOException;
|
| 23 | +import java.util.List; |
23 | 24 | import org.apache.hadoop.conf.Configuration;
|
24 | 25 | import org.apache.hadoop.fs.FileStatus;
|
25 | 26 | import org.apache.hadoop.fs.FileSystem;
|
26 | 27 | import org.apache.hadoop.fs.Path;
|
27 | 28 | import org.apache.hadoop.hbase.HBaseIOException;
|
28 | 29 | import org.apache.hadoop.hbase.Server;
|
29 | 30 | import org.apache.hadoop.hbase.TableName;
|
| 31 | +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; |
30 | 32 | import org.apache.hadoop.hbase.client.Get;
|
31 | 33 | import org.apache.hadoop.hbase.client.RegionInfo;
|
32 | 34 | import org.apache.hadoop.hbase.client.RegionInfoBuilder;
|
33 | 35 | import org.apache.hadoop.hbase.client.Result;
|
34 | 36 | import org.apache.hadoop.hbase.client.ResultScanner;
|
35 | 37 | import org.apache.hadoop.hbase.client.Scan;
|
36 | 38 | import org.apache.hadoop.hbase.client.TableDescriptor;
|
| 39 | +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; |
37 | 40 | import org.apache.hadoop.hbase.regionserver.HRegion;
|
38 | 41 | import org.apache.hadoop.hbase.regionserver.HRegion.FlushResult;
|
39 | 42 | import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
|
40 | 43 | import org.apache.hadoop.hbase.regionserver.RegionScanner;
|
| 44 | +import org.apache.hadoop.hbase.regionserver.StoreFileInfo; |
| 45 | +import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTracker; |
| 46 | +import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory; |
41 | 47 | import org.apache.hadoop.hbase.regionserver.wal.AbstractFSWAL;
|
42 | 48 | import org.apache.hadoop.hbase.util.Bytes;
|
43 | 49 | import org.apache.hadoop.hbase.util.CommonFSUtils;
|
| 50 | +import org.apache.hadoop.hbase.util.FSTableDescriptors; |
44 | 51 | import org.apache.hadoop.hbase.util.FSUtils;
|
45 | 52 | import org.apache.hadoop.hbase.util.HFileArchiveUtil;
|
46 | 53 | import org.apache.hadoop.hbase.util.RecoverLeaseFSUtils;
|
@@ -92,6 +99,10 @@ public final class MasterRegion {
|
92 | 99 |
|
93 | 100 | private static final String DEAD_WAL_DIR_SUFFIX = "-dead";
|
94 | 101 |
|
| 102 | + static final String INITIALIZING_FLAG = ".initializing"; |
| 103 | + |
| 104 | + static final String INITIALIZED_FLAG = ".initialized"; |
| 105 | + |
95 | 106 | private static final int REGION_ID = 1;
|
96 | 107 |
|
97 | 108 | private final WALFactory walFactory;
|
@@ -196,32 +207,39 @@ private static WAL createWAL(WALFactory walFactory, MasterRegionWALRoller walRol
|
196 | 207 |
|
197 | 208 | private static HRegion bootstrap(Configuration conf, TableDescriptor td, FileSystem fs,
|
198 | 209 | Path rootDir, FileSystem walFs, Path walRootDir, WALFactory walFactory,
|
199 |
| - MasterRegionWALRoller walRoller, String serverName) throws IOException { |
| 210 | + MasterRegionWALRoller walRoller, String serverName, boolean touchInitializingFlag) |
| 211 | + throws IOException { |
200 | 212 | TableName tn = td.getTableName();
|
201 | 213 | RegionInfo regionInfo = RegionInfoBuilder.newBuilder(tn).setRegionId(REGION_ID).build();
|
202 |
| - Path tmpTableDir = CommonFSUtils.getTableDir(rootDir, |
203 |
| - TableName.valueOf(tn.getNamespaceAsString(), tn.getQualifierAsString() + "-tmp")); |
204 |
| - if (fs.exists(tmpTableDir) && !fs.delete(tmpTableDir, true)) { |
205 |
| - throw new IOException("Can not delete partial created proc region " + tmpTableDir); |
206 |
| - } |
207 |
| - HRegion.createHRegion(conf, regionInfo, fs, tmpTableDir, td).close(); |
208 | 214 | Path tableDir = CommonFSUtils.getTableDir(rootDir, tn);
|
209 |
| - if (!fs.rename(tmpTableDir, tableDir)) { |
210 |
| - throw new IOException("Can not rename " + tmpTableDir + " to " + tableDir); |
| 215 | + // persist table descriptor |
| 216 | + FSTableDescriptors.createTableDescriptorForTableDirectory(fs, tableDir, td, true); |
| 217 | + HRegion.createHRegion(conf, regionInfo, fs, tableDir, td).close(); |
| 218 | + Path initializedFlag = new Path(tableDir, INITIALIZED_FLAG); |
| 219 | + if (!fs.mkdirs(initializedFlag)) { |
| 220 | + throw new IOException("Can not touch initialized flag: " + initializedFlag); |
| 221 | + } |
| 222 | + Path initializingFlag = new Path(tableDir, INITIALIZING_FLAG); |
| 223 | + if (!fs.delete(initializingFlag, true)) { |
| 224 | + LOG.warn("failed to clean up initializing flag: " + initializingFlag); |
211 | 225 | }
|
212 | 226 | WAL wal = createWAL(walFactory, walRoller, serverName, walFs, walRootDir, regionInfo);
|
213 | 227 | return HRegion.openHRegionFromTableDir(conf, fs, tableDir, regionInfo, td, wal, null, null);
|
214 | 228 | }
|
215 | 229 |
|
216 |
| - private static HRegion open(Configuration conf, TableDescriptor td, FileSystem fs, Path rootDir, |
217 |
| - FileSystem walFs, Path walRootDir, WALFactory walFactory, MasterRegionWALRoller walRoller, |
218 |
| - String serverName) throws IOException { |
219 |
| - Path tableDir = CommonFSUtils.getTableDir(rootDir, td.getTableName()); |
220 |
| - Path regionDir = |
221 |
| - fs.listStatus(tableDir, p -> RegionInfo.isEncodedRegionName(Bytes.toBytes(p.getName())))[0] |
222 |
| - .getPath(); |
223 |
| - RegionInfo regionInfo = HRegionFileSystem.loadRegionInfoFileContent(fs, regionDir); |
| 230 | + private static RegionInfo loadRegionInfo(FileSystem fs, Path tableDir) throws IOException { |
| 231 | + // on branch-2, the RegionInfo.isEncodedRegionName will returns true for .initializing and |
| 232 | + // .initialized, see HBASE-25368. Since RegionInfo is IA.Public, changing the implementation may |
| 233 | + // raise compatibility concerns, so here we just skip them by our own. |
| 234 | + Path regionDir = fs.listStatus(tableDir, p -> !p.getName().startsWith(".") |
| 235 | + && RegionInfo.isEncodedRegionName(Bytes.toBytes(p.getName())))[0].getPath(); |
| 236 | + return HRegionFileSystem.loadRegionInfoFileContent(fs, regionDir); |
| 237 | + } |
224 | 238 |
|
| 239 | + private static HRegion open(Configuration conf, TableDescriptor td, RegionInfo regionInfo, |
| 240 | + FileSystem fs, Path rootDir, FileSystem walFs, Path walRootDir, WALFactory walFactory, |
| 241 | + MasterRegionWALRoller walRoller, String serverName) throws IOException { |
| 242 | + Path tableDir = CommonFSUtils.getTableDir(rootDir, td.getTableName()); |
225 | 243 | Path walRegionDir = FSUtils.getRegionDirFromRootDir(walRootDir, regionInfo);
|
226 | 244 | Path replayEditsDir = new Path(walRegionDir, REPLAY_EDITS_DIR);
|
227 | 245 | if (!walFs.exists(replayEditsDir) && !walFs.mkdirs(replayEditsDir)) {
|
@@ -287,6 +305,39 @@ private static void replayWALs(Configuration conf, FileSystem walFs, Path walRoo
|
287 | 305 | }
|
288 | 306 | }
|
289 | 307 |
|
| 308 | + private static void tryMigrate(Configuration conf, FileSystem fs, Path tableDir, |
| 309 | + RegionInfo regionInfo, TableDescriptor oldTd, TableDescriptor newTd) throws IOException { |
| 310 | + Class<? extends StoreFileTracker> oldSft = |
| 311 | + StoreFileTrackerFactory.getTrackerClass(oldTd.getValue(StoreFileTrackerFactory.TRACKER_IMPL)); |
| 312 | + Class<? extends StoreFileTracker> newSft = |
| 313 | + StoreFileTrackerFactory.getTrackerClass(newTd.getValue(StoreFileTrackerFactory.TRACKER_IMPL)); |
| 314 | + if (oldSft.equals(newSft)) { |
| 315 | + LOG.debug("old store file tracker {} is the same with new store file tracker, skip migration", |
| 316 | + StoreFileTrackerFactory.getStoreFileTrackerName(oldSft)); |
| 317 | + if (!oldTd.equals(newTd)) { |
| 318 | + // we may change other things such as adding a new family, so here we still need to persist |
| 319 | + // the new table descriptor |
| 320 | + LOG.info("Update table descriptor from {} to {}", oldTd, newTd); |
| 321 | + FSTableDescriptors.createTableDescriptorForTableDirectory(fs, tableDir, newTd, true); |
| 322 | + } |
| 323 | + return; |
| 324 | + } |
| 325 | + LOG.info("Migrate store file tracker from {} to {}", oldSft.getSimpleName(), |
| 326 | + newSft.getSimpleName()); |
| 327 | + HRegionFileSystem hfs = |
| 328 | + HRegionFileSystem.openRegionFromFileSystem(conf, fs, tableDir, regionInfo, false); |
| 329 | + for (ColumnFamilyDescriptor oldCfd : oldTd.getColumnFamilies()) { |
| 330 | + StoreFileTracker oldTracker = StoreFileTrackerFactory.create(conf, oldTd, oldCfd, hfs); |
| 331 | + StoreFileTracker newTracker = StoreFileTrackerFactory.create(conf, oldTd, oldCfd, hfs); |
| 332 | + List<StoreFileInfo> files = oldTracker.load(); |
| 333 | + LOG.debug("Store file list for {}: {}", oldCfd.getNameAsString(), files); |
| 334 | + newTracker.set(oldTracker.load()); |
| 335 | + } |
| 336 | + // persist the new table descriptor after migration |
| 337 | + LOG.info("Update table descriptor from {} to {}", oldTd, newTd); |
| 338 | + FSTableDescriptors.createTableDescriptorForTableDirectory(fs, tableDir, newTd, true); |
| 339 | + } |
| 340 | + |
290 | 341 | public static MasterRegion create(MasterRegionParams params) throws IOException {
|
291 | 342 | TableDescriptor td = params.tableDescriptor();
|
292 | 343 | LOG.info("Create or load local region for table " + td);
|
@@ -321,16 +372,58 @@ public static MasterRegion create(MasterRegionParams params) throws IOException
|
321 | 372 |
|
322 | 373 | WALFactory walFactory = new WALFactory(conf, server.getServerName().toString());
|
323 | 374 | Path tableDir = CommonFSUtils.getTableDir(rootDir, td.getTableName());
|
| 375 | + Path initializingFlag = new Path(tableDir, INITIALIZING_FLAG); |
| 376 | + Path initializedFlag = new Path(tableDir, INITIALIZED_FLAG); |
324 | 377 | HRegion region;
|
325 |
| - if (fs.exists(tableDir)) { |
326 |
| - // load the existing region. |
327 |
| - region = open(conf, td, fs, rootDir, walFs, walRootDir, walFactory, walRoller, |
328 |
| - server.getServerName().toString()); |
329 |
| - } else { |
330 |
| - // bootstrapping... |
| 378 | + if (!fs.exists(tableDir)) { |
| 379 | + // bootstrap, no doubt |
| 380 | + if (!fs.mkdirs(initializedFlag)) { |
| 381 | + throw new IOException("Can not touch initialized flag"); |
| 382 | + } |
331 | 383 | region = bootstrap(conf, td, fs, rootDir, walFs, walRootDir, walFactory, walRoller,
|
332 |
| - server.getServerName().toString()); |
| 384 | + server.getServerName().toString(), true); |
| 385 | + } else { |
| 386 | + if (!fs.exists(initializedFlag)) { |
| 387 | + if (!fs.exists(initializingFlag)) { |
| 388 | + // should be old style, where we do not have the initializing or initialized file, persist |
| 389 | + // the table descriptor, touch the initialized flag and then open the region. |
| 390 | + // the store file tracker must be DEFAULT |
| 391 | + LOG.info("No {} or {} file, try upgrading", INITIALIZING_FLAG, INITIALIZED_FLAG); |
| 392 | + TableDescriptor oldTd = |
| 393 | + TableDescriptorBuilder.newBuilder(td).setValue(StoreFileTrackerFactory.TRACKER_IMPL, |
| 394 | + StoreFileTrackerFactory.Trackers.DEFAULT.name()).build(); |
| 395 | + FSTableDescriptors.createTableDescriptorForTableDirectory(fs, tableDir, oldTd, true); |
| 396 | + if (!fs.mkdirs(initializedFlag)) { |
| 397 | + throw new IOException("Can not touch initialized flag: " + initializedFlag); |
| 398 | + } |
| 399 | + RegionInfo regionInfo = loadRegionInfo(fs, tableDir); |
| 400 | + tryMigrate(conf, fs, tableDir, regionInfo, oldTd, td); |
| 401 | + region = open(conf, td, regionInfo, fs, rootDir, walFs, walRootDir, walFactory, walRoller, |
| 402 | + server.getServerName().toString()); |
| 403 | + } else { |
| 404 | + // delete all contents besides the initializing flag, here we can make sure tableDir |
| 405 | + // exists(unless someone delete it manually...), so we do not do null check here. |
| 406 | + for (FileStatus status : fs.listStatus(tableDir)) { |
| 407 | + if (!status.getPath().getName().equals(INITIALIZING_FLAG)) { |
| 408 | + fs.delete(status.getPath(), true); |
| 409 | + } |
| 410 | + } |
| 411 | + region = bootstrap(conf, td, fs, rootDir, walFs, walRootDir, walFactory, walRoller, |
| 412 | + server.getServerName().toString(), false); |
| 413 | + } |
| 414 | + } else { |
| 415 | + if (fs.exists(initializingFlag) && !fs.delete(initializingFlag, true)) { |
| 416 | + LOG.warn("failed to clean up initializing flag: " + initializingFlag); |
| 417 | + } |
| 418 | + // open it, make sure to load the table descriptor from fs |
| 419 | + TableDescriptor oldTd = FSTableDescriptors.getTableDescriptorFromFs(fs, tableDir); |
| 420 | + RegionInfo regionInfo = loadRegionInfo(fs, tableDir); |
| 421 | + tryMigrate(conf, fs, tableDir, regionInfo, oldTd, td); |
| 422 | + region = open(conf, td, regionInfo, fs, rootDir, walFs, walRootDir, walFactory, walRoller, |
| 423 | + server.getServerName().toString()); |
| 424 | + } |
333 | 425 | }
|
| 426 | + |
334 | 427 | Path globalArchiveDir = HFileArchiveUtil.getArchivePath(baseConf);
|
335 | 428 | MasterRegionFlusherAndCompactor flusherAndCompactor = new MasterRegionFlusherAndCompactor(conf,
|
336 | 429 | server, region, params.flushSize(), params.flushPerChanges(), params.flushIntervalMs(),
|
|
0 commit comments