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