From adec53fc30e4097722043948d951a0bde19abd08 Mon Sep 17 00:00:00 2001 From: Michael Stack Date: Tue, 19 Dec 2017 22:26:28 -0800 Subject: [PATCH 2/2] HBASE-19562 Purge mirror writing of region and table info into fs at .tableinfo and .regioninfo --- .../hadoop/hbase/backup/util/BackupUtils.java | 17 - .../hadoop/hbase/TableInfoMissingException.java | 47 -- .../hbase/client/TableDescriptorBuilder.java | 1 - .../hadoop/hbase/master/MasterFileSystem.java | 77 +- .../master/snapshot/MasterSnapshotVerifier.java | 3 - .../hbase/master/snapshot/TakeSnapshotHandler.java | 10 - .../apache/hadoop/hbase/regionserver/HRegion.java | 11 - .../hbase/regionserver/HRegionFileSystem.java | 166 +---- .../hadoop/hbase/regionserver/HRegionServer.java | 1 - .../hbase/snapshot/SnapshotDescriptionUtils.java | 2 - .../hadoop/hbase/snapshot/SnapshotManifest.java | 91 +-- .../hadoop/hbase/util/FSTableDescriptors.java | 802 --------------------- .../java/org/apache/hadoop/hbase/util/FSUtils.java | 3 +- 13 files changed, 74 insertions(+), 1157 deletions(-) delete mode 100644 hbase-client/src/main/java/org/apache/hadoop/hbase/TableInfoMissingException.java delete mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSTableDescriptors.java diff --git a/hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/util/BackupUtils.java b/hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/util/BackupUtils.java index 9d87612e0f..859023adca 100644 --- a/hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/util/BackupUtils.java +++ b/hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/util/BackupUtils.java @@ -144,12 +144,6 @@ public final class BackupUtils { // write a copy of descriptor to the target directory Path target = new Path(backupInfo.getTableBackupDir(table)); FileSystem targetFs = target.getFileSystem(conf); - FSTableDescriptors descriptors = - new FSTableDescriptors(conf, targetFs, FSUtils.getRootDir(conf)); - descriptors.createTableDescriptorForTableDirectory(target, orig, false); - LOG.debug("Attempting to copy table info for:" + table + " target: " + target - + " descriptor: " + orig); - LOG.debug("Finished copying tableinfo."); List regions = null; regions = MetaTableAccessor.getTableRegions(conn, table); // For each region, write the region info to disk @@ -169,17 +163,6 @@ public final class BackupUtils { */ public static void writeRegioninfoOnFilesystem(final Configuration conf, final FileSystem fs, final Path regionInfoDir, RegionInfo regionInfo) throws IOException { - final byte[] content = RegionInfo.toDelimitedByteArray(regionInfo); - Path regionInfoFile = new Path(regionInfoDir, "." + HConstants.REGIONINFO_QUALIFIER_STR); - // First check to get the permissions - FsPermission perms = FSUtils.getFilePermissions(fs, conf, HConstants.DATA_FILE_UMASK_KEY); - // Write the RegionInfo file content - FSDataOutputStream out = FSUtils.create(conf, fs, regionInfoFile, perms, null); - try { - out.write(content); - } finally { - out.close(); - } } /** diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/TableInfoMissingException.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/TableInfoMissingException.java deleted file mode 100644 index 09d0b2bb19..0000000000 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/TableInfoMissingException.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.hadoop.hbase; - -import org.apache.yetus.audience.InterfaceAudience; - -/** - * - * Failed to find .tableinfo file under table dir - * - */ -@InterfaceAudience.Public -@SuppressWarnings("serial") -public class TableInfoMissingException extends HBaseIOException { - - public TableInfoMissingException() { - super(); - } - - public TableInfoMissingException( String message ) { - super(message); - } - - public TableInfoMissingException( String message, Throwable t ) { - super(message, t); - } - - public TableInfoMissingException( Throwable t ) { - super(t); - } - -} diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java index 5c4f7210c9..7115d6562c 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java @@ -1423,5 +1423,4 @@ public class TableDescriptorBuilder { return families.size(); } } - } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java index 27987f6bce..6837a03f73 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java @@ -1,5 +1,4 @@ -/** - * +/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -22,12 +21,14 @@ import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.curator.shaded.com.google.common.annotations.VisibleForTesting; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hbase.ClusterId; +import org.apache.hadoop.hbase.Coprocessor; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.backup.HFileArchiver; @@ -41,9 +42,9 @@ import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.fs.HFileSystem; import org.apache.hadoop.hbase.mob.MobConstants; import org.apache.hadoop.hbase.procedure2.store.wal.WALProcedureStore; +import org.apache.hadoop.hbase.regionserver.BloomType; import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.FSTableDescriptors; import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.ipc.RemoteException; import org.apache.yetus.audience.InterfaceAudience; @@ -285,13 +286,6 @@ public class MasterFileSystem { bootstrap(rd, c); } - // Create tableinfo-s for hbase:meta if not already there. - // assume, created table descriptor is for enabling table - // meta table is a system table, so descriptors are predefined, - // we should get them from registry. - FSTableDescriptors fsd = new FSTableDescriptors(c, fs, rd); - fsd.createTableDescriptor(fsd.get(TableName.META_TABLE_NAME)); - return rd; } @@ -389,7 +383,7 @@ public class MasterFileSystem { // created here in bootstrap and it'll need to be cleaned up. Better to // not make it in first place. Turn off block caching for bootstrap. // Enable after. - TableDescriptor metaDescriptor = new FSTableDescriptors(c).get(TableName.META_TABLE_NAME); + TableDescriptor metaDescriptor = createMetaTableDescriptorBuilder(c).build(); HRegion meta = HRegion.createHRegion(RegionInfoBuilder.FIRST_META_REGIONINFO, rd, c, setInfoFamilyCachingForMeta(metaDescriptor, false), null); meta.close(); @@ -447,4 +441,65 @@ public class MasterFileSystem { public void logFileSystemState(Log log) throws IOException { FSUtils.logFileSystemState(fs, rootdir, log); } + + + @VisibleForTesting + public static TableDescriptorBuilder createMetaTableDescriptorBuilder(final Configuration conf) + throws IOException { + // TODO We used to set CacheDataInL1 for META table. When we have BucketCache in file mode, now + // the META table data goes to File mode BC only. Test how that affect the system. If too much, + // we have to rethink about adding back the setCacheDataInL1 for META table CFs. + return TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME) + .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.CATALOG_FAMILY) + .setMaxVersions(conf.getInt(HConstants.HBASE_META_VERSIONS, + HConstants.DEFAULT_HBASE_META_VERSIONS)) + .setInMemory(true) + .setBlocksize(conf.getInt(HConstants.HBASE_META_BLOCK_SIZE, + HConstants.DEFAULT_HBASE_META_BLOCK_SIZE)) + .setScope(HConstants.REPLICATION_SCOPE_LOCAL) + // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. + .setBloomFilterType(BloomType.NONE) + .build()) + .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.REPLICATION_BARRIER_FAMILY) + .setMaxVersions(conf.getInt(HConstants.HBASE_META_VERSIONS, + HConstants.DEFAULT_HBASE_META_VERSIONS)) + .setInMemory(true) + .setBlocksize(conf.getInt(HConstants.HBASE_META_BLOCK_SIZE, + HConstants.DEFAULT_HBASE_META_BLOCK_SIZE)) + .setScope(HConstants.REPLICATION_SCOPE_LOCAL) + // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. + .setBloomFilterType(BloomType.NONE) + .build()) + .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.REPLICATION_POSITION_FAMILY) + .setMaxVersions(conf.getInt(HConstants.HBASE_META_VERSIONS, + HConstants.DEFAULT_HBASE_META_VERSIONS)) + .setInMemory(true) + .setBlocksize(conf.getInt(HConstants.HBASE_META_BLOCK_SIZE, + HConstants.DEFAULT_HBASE_META_BLOCK_SIZE)) + .setScope(HConstants.REPLICATION_SCOPE_LOCAL) + // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. + .setBloomFilterType(BloomType.NONE) + .build()) + .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.REPLICATION_META_FAMILY) + .setMaxVersions(conf.getInt(HConstants.HBASE_META_VERSIONS, + HConstants.DEFAULT_HBASE_META_VERSIONS)) + .setInMemory(true) + .setBlocksize(conf.getInt(HConstants.HBASE_META_BLOCK_SIZE, + HConstants.DEFAULT_HBASE_META_BLOCK_SIZE)) + .setScope(HConstants.REPLICATION_SCOPE_LOCAL) + // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. + .setBloomFilterType(BloomType.NONE) + .build()) + .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.TABLE_FAMILY) + // Ten is arbitrary number. Keep versions to help debugging. + .setMaxVersions(10) + .setInMemory(true) + .setBlocksize(8 * 1024) + .setScope(HConstants.REPLICATION_SCOPE_LOCAL) + // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. + .setBloomFilterType(BloomType.NONE) + .build()) + .addCoprocessor("org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint", + null, Coprocessor.PRIORITY_SYSTEM, null); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java index b698082f74..2a0334df43 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java @@ -113,9 +113,6 @@ public final class MasterSnapshotVerifier { // verify snapshot info matches verifySnapshotDescription(snapshotDir); - // check that tableinfo is a valid table description - verifyTableInfo(manifest); - // check that each region is valid verifyRegions(manifest); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java index 808cab5b35..6fd2a909ec 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java @@ -125,16 +125,6 @@ public abstract class TakeSnapshotHandler extends EventHandler implements Snapsh "Taking " + snapshot.getType() + " snapshot on table: " + snapshotTable); } - private TableDescriptor loadTableDescriptor() - throws FileNotFoundException, IOException { - TableDescriptor htd = - this.master.getTableDescriptors().get(snapshotTable); - if (htd == null) { - throw new IOException("TableDescriptor missing for " + snapshotTable); - } - return htd; - } - @Override public TakeSnapshotHandler prepare() throws Exception { super.prepare(); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java index 98e9df66c8..916c68d035 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java @@ -885,17 +885,6 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi coprocessorHost.preOpen(); } - // Write HRI to a file in case we need to recover hbase:meta - // Only the primary replica should write .regioninfo - if (this.getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) { - status.setStatus("Writing region info on filesystem"); - fs.checkRegionInfoOnFilesystem(); - } else { - if (LOG.isDebugEnabled()) { - LOG.debug("Skipping creation of .regioninfo file for " + this.getRegionInfo()); - } - } - // Initialize all the HStores status.setStatus("Initializing all the Stores"); long maxSeqId = initializeStores(reporter, status); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java index 4fc9ffe5cd..95c3fade94 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java @@ -1,5 +1,4 @@ -/** - * +/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -31,8 +30,6 @@ import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.FSDataInputStream; -import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileUtil; @@ -67,9 +64,6 @@ import edu.umd.cs.findbugs.annotations.Nullable; public class HRegionFileSystem { private static final Log LOG = LogFactory.getLog(HRegionFileSystem.class); - /** Name of the region info file that resides just under the region directory. */ - public final static String REGION_INFO_FILE = ".regioninfo"; - /** Temporary subdirectory of the region directory used for merges. */ public static final String REGION_MERGES_DIR = ".merges"; @@ -612,12 +606,6 @@ public class HRegionFileSystem { Path daughterTmpDir = this.getSplitsDir(regionInfo); if (fs.exists(daughterTmpDir)) { - - // Write HRI to a file in case we need to recover hbase:meta - Path regionInfoFile = new Path(daughterTmpDir, REGION_INFO_FILE); - byte[] regionInfoContent = getRegionInfoFileContent(regionInfo); - writeRegionInfoFileContent(conf, fs, regionInfoFile, regionInfoContent); - // Move the daughter temp dir to the table dir if (!rename(daughterTmpDir, regionDir)) { throw new IOException("Unable to rename " + daughterTmpDir + " to " + regionDir); @@ -825,139 +813,6 @@ public class HRegionFileSystem { } /** - * @param hri - * @return Content of the file we write out to the filesystem under a region - * @throws IOException - */ - private static byte[] getRegionInfoFileContent(final RegionInfo hri) throws IOException { - return RegionInfo.toDelimitedByteArray(hri); - } - - /** - * Create a {@link RegionInfo} from the serialized version on-disk. - * @param fs {@link FileSystem} that contains the Region Info file - * @param regionDir {@link Path} to the Region Directory that contains the Info file - * @return An {@link RegionInfo} instance gotten from the Region Info file. - * @throws IOException if an error occurred during file open/read operation. - */ - public static RegionInfo loadRegionInfoFileContent(final FileSystem fs, final Path regionDir) - throws IOException { - FSDataInputStream in = fs.open(new Path(regionDir, REGION_INFO_FILE)); - try { - return RegionInfo.parseFrom(in); - } finally { - in.close(); - } - } - - /** - * Write the .regioninfo file on-disk. - */ - private static void writeRegionInfoFileContent(final Configuration conf, final FileSystem fs, - final Path regionInfoFile, final byte[] content) throws IOException { - // First check to get the permissions - FsPermission perms = FSUtils.getFilePermissions(fs, conf, HConstants.DATA_FILE_UMASK_KEY); - // Write the RegionInfo file content - FSDataOutputStream out = FSUtils.create(conf, fs, regionInfoFile, perms, null); - try { - out.write(content); - } finally { - out.close(); - } - } - - /** - * Write out an info file under the stored region directory. Useful recovering mangled regions. - * If the regionInfo already exists on-disk, then we fast exit. - */ - void checkRegionInfoOnFilesystem() throws IOException { - // Compose the content of the file so we can compare to length in filesystem. If not same, - // rewrite it (it may have been written in the old format using Writables instead of pb). The - // pb version is much shorter -- we write now w/o the toString version -- so checking length - // only should be sufficient. I don't want to read the file every time to check if it pb - // serialized. - byte[] content = getRegionInfoFileContent(regionInfoForFs); - - // Verify if the region directory exists before opening a region. We need to do this since if - // the region directory doesn't exist we will re-create the region directory and a new HRI - // when HRegion.openHRegion() is called. - try { - FileStatus status = fs.getFileStatus(getRegionDir()); - } catch (FileNotFoundException e) { - LOG.warn(getRegionDir() + " doesn't exist for region: " + regionInfoForFs.getEncodedName() + - " on table " + regionInfo.getTable()); - } - - try { - Path regionInfoFile = new Path(getRegionDir(), REGION_INFO_FILE); - FileStatus status = fs.getFileStatus(regionInfoFile); - if (status != null && status.getLen() == content.length) { - // Then assume the content good and move on. - // NOTE: that the length is not sufficient to define the the content matches. - return; - } - - LOG.info("Rewriting .regioninfo file at: " + regionInfoFile); - if (!fs.delete(regionInfoFile, false)) { - throw new IOException("Unable to remove existing " + regionInfoFile); - } - } catch (FileNotFoundException e) { - LOG.warn(REGION_INFO_FILE + " file not found for region: " + regionInfoForFs.getEncodedName() + - " on table " + regionInfo.getTable()); - } - - // Write HRI to a file in case we need to recover hbase:meta - writeRegionInfoOnFilesystem(content, true); - } - - /** - * Write out an info file under the region directory. Useful recovering mangled regions. - * @param useTempDir indicate whether or not using the region .tmp dir for a safer file creation. - */ - private void writeRegionInfoOnFilesystem(boolean useTempDir) throws IOException { - byte[] content = getRegionInfoFileContent(regionInfoForFs); - writeRegionInfoOnFilesystem(content, useTempDir); - } - - /** - * Write out an info file under the region directory. Useful recovering mangled regions. - * @param regionInfoContent serialized version of the {@link RegionInfo} - * @param useTempDir indicate whether or not using the region .tmp dir for a safer file creation. - */ - private void writeRegionInfoOnFilesystem(final byte[] regionInfoContent, - final boolean useTempDir) throws IOException { - Path regionInfoFile = new Path(getRegionDir(), REGION_INFO_FILE); - if (useTempDir) { - // Create in tmpDir and then move into place in case we crash after - // create but before close. If we don't successfully close the file, - // subsequent region reopens will fail the below because create is - // registered in NN. - - // And then create the file - Path tmpPath = new Path(getTempDir(), REGION_INFO_FILE); - - // If datanode crashes or if the RS goes down just before the close is called while trying to - // close the created regioninfo file in the .tmp directory then on next - // creation we will be getting AlreadyCreatedException. - // Hence delete and create the file if exists. - if (FSUtils.isExists(fs, tmpPath)) { - FSUtils.delete(fs, tmpPath, true); - } - - // Write HRI to a file in case we need to recover hbase:meta - writeRegionInfoFileContent(conf, fs, tmpPath, regionInfoContent); - - // Move the created file to the original path - if (fs.exists(tmpPath) && !rename(tmpPath, regionInfoFile)) { - throw new IOException("Unable to rename " + tmpPath + " to " + regionInfoFile); - } - } else { - // Write HRI to a file in case we need to recover hbase:meta - writeRegionInfoFileContent(conf, fs, regionInfoFile, regionInfoContent); - } - } - - /** * Create a new Region on file-system. * @param conf the {@link Configuration} to use * @param fs {@link FileSystem} from which to add the region @@ -980,15 +835,6 @@ public class HRegionFileSystem { LOG.warn("Unable to create the region directory: " + regionDir); throw new IOException("Unable to create region directory: " + regionDir); } - - // Write HRI to a file in case we need to recover hbase:meta - // Only primary replicas should write region info - if (regionInfo.getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) { - regionFs.writeRegionInfoOnFilesystem(false); - } else { - if (LOG.isDebugEnabled()) - LOG.debug("Skipping creation of .regioninfo file for " + regionInfo); - } return regionFs; } @@ -1017,16 +863,6 @@ public class HRegionFileSystem { regionFs.cleanupTempDir(); regionFs.cleanupSplitsDir(); regionFs.cleanupMergesDir(); - - // If it doesn't exists, Write HRI to a file, in case we need to recover hbase:meta - // Only create HRI if we are the default replica - if (regionInfo.getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) { - regionFs.checkRegionInfoOnFilesystem(); - } else { - if (LOG.isDebugEnabled()) { - LOG.debug("Skipping creation of .regioninfo file for " + regionInfo); - } - } } return regionFs; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index e2d6ba061b..084a02662a 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -144,7 +144,6 @@ import org.apache.hadoop.hbase.util.Addressing; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.CompressionTest; import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; -import org.apache.hadoop.hbase.util.FSTableDescriptors; import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.hbase.util.HasThread; import org.apache.hadoop.hbase.util.JvmPauseMonitor; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java index 61a4a85ed0..bd8862c033 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java @@ -62,13 +62,11 @@ import org.apache.hadoop.hbase.util.FSUtils; *
  * /hbase/.snapshots/completed
  *                   .snapshotinfo          <--- Description of the snapshot
- *                   .tableinfo             <--- Copy of the tableinfo
  *                    /.logs
  *                        /[server_name]
  *                            /... [log files]
  *                         ...
  *                   /[region name]           <---- All the region's information
- *                   .regioninfo              <---- Copy of the HRegionInfo
  *                      /[column family name]
  *                          /[hfile name]     <--- name of the hfile in the real region
  *                          ...
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotManifest.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotManifest.java
index 1a7c7f017a..6332926b94 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotManifest.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotManifest.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -47,7 +47,6 @@ import org.apache.hadoop.hbase.regionserver.HStore;
 import org.apache.hadoop.hbase.regionserver.HStoreFile;
 import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
 import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.util.FSTableDescriptors;
 import org.apache.hadoop.hbase.util.FSUtils;
 import org.apache.hadoop.hbase.util.Threads;
 import org.apache.yetus.audience.InterfaceAudience;
@@ -155,7 +154,7 @@ public final class SnapshotManifest {
   private RegionVisitor createRegionVisitor(final SnapshotDescription desc) throws IOException {
     switch (getSnapshotFormat(desc)) {
       case SnapshotManifestV1.DESCRIPTOR_VERSION:
-        return new SnapshotManifestV1.ManifestBuilder(conf, fs, workingDir);
+        throw new UnsupportedOperationException("hbase-2.x does not read manifest v1");
       case SnapshotManifestV2.DESCRIPTOR_VERSION:
         return new SnapshotManifestV2.ManifestBuilder(conf, fs, workingDir);
       default:
@@ -365,15 +364,7 @@ public final class SnapshotManifest {
   private void load() throws IOException {
     switch (getSnapshotFormat(desc)) {
       case SnapshotManifestV1.DESCRIPTOR_VERSION: {
-        this.htd = FSTableDescriptors.getTableDescriptorFromFs(fs, workingDir);
-        ThreadPoolExecutor tpool = createExecutor("SnapshotManifestLoader");
-        try {
-          this.regionManifests =
-            SnapshotManifestV1.loadRegionManifests(conf, tpool, fs, workingDir, desc);
-        } finally {
-          tpool.shutdown();
-        }
-        break;
+        throw new UnsupportedOperationException("hbase-2.x does not read manifest v1");
       }
       case SnapshotManifestV2.DESCRIPTOR_VERSION: {
         SnapshotDataManifest dataManifest = readDataManifest();
@@ -383,10 +374,9 @@ public final class SnapshotManifest {
         } else {
           // Compatibility, load the v1 regions
           // This happens only when the snapshot is in-progress and the cache wants to refresh.
-          List v1Regions, v2Regions;
+          List v2Regions;
           ThreadPoolExecutor tpool = createExecutor("SnapshotManifestLoader");
           try {
-            v1Regions = SnapshotManifestV1.loadRegionManifests(conf, tpool, fs, workingDir, desc);
             v2Regions = SnapshotManifestV2.loadRegionManifests(conf, tpool, fs, workingDir, desc,
                 manifestSizeLimit);
           } catch (InvalidProtocolBufferException e) {
@@ -395,14 +385,9 @@ public final class SnapshotManifest {
           } finally {
             tpool.shutdown();
           }
-          if (v1Regions != null && v2Regions != null) {
-            regionManifests = new ArrayList<>(v1Regions.size() + v2Regions.size());
-            regionManifests.addAll(v1Regions);
+          if (v2Regions != null) {
+            regionManifests = new ArrayList<>(v2Regions.size());
             regionManifests.addAll(v2Regions);
-          } else if (v1Regions != null) {
-            regionManifests = v1Regions;
-          } else /* if (v2Regions != null) */ {
-            regionManifests = v2Regions;
           }
         }
         break;
@@ -456,70 +441,6 @@ public final class SnapshotManifest {
     return regionsMap;
   }
 
-  public void consolidate() throws IOException {
-    if (getSnapshotFormat(desc) == SnapshotManifestV1.DESCRIPTOR_VERSION) {
-      Path rootDir = FSUtils.getRootDir(conf);
-      LOG.info("Using old Snapshot Format");
-      // write a copy of descriptor to the snapshot directory
-      new FSTableDescriptors(conf, fs, rootDir)
-        .createTableDescriptorForTableDirectory(workingDir, htd, false);
-    } else {
-      LOG.debug("Convert to Single Snapshot Manifest");
-      convertToV2SingleManifest();
-    }
-  }
-
-  /*
-   * In case of rolling-upgrade, we try to read all the formats and build
-   * the snapshot with the latest format.
-   */
-  private void convertToV2SingleManifest() throws IOException {
-    // Try to load v1 and v2 regions
-    List v1Regions, v2Regions;
-    ThreadPoolExecutor tpool = createExecutor("SnapshotManifestLoader");
-    try {
-      v1Regions = SnapshotManifestV1.loadRegionManifests(conf, tpool, fs, workingDir, desc);
-      v2Regions = SnapshotManifestV2.loadRegionManifests(conf, tpool, fs, workingDir, desc,
-          manifestSizeLimit);
-    } finally {
-      tpool.shutdown();
-    }
-
-    SnapshotDataManifest.Builder dataManifestBuilder = SnapshotDataManifest.newBuilder();
-    dataManifestBuilder.setTableSchema(ProtobufUtil.toTableSchema(htd));
-
-    if (v1Regions != null && v1Regions.size() > 0) {
-      dataManifestBuilder.addAllRegionManifests(v1Regions);
-    }
-    if (v2Regions != null && v2Regions.size() > 0) {
-      dataManifestBuilder.addAllRegionManifests(v2Regions);
-    }
-
-    // Write the v2 Data Manifest.
-    // Once the data-manifest is written, the snapshot can be considered complete.
-    // Currently snapshots are written in a "temporary" directory and later
-    // moved to the "complated" snapshot directory.
-    SnapshotDataManifest dataManifest = dataManifestBuilder.build();
-    writeDataManifest(dataManifest);
-    this.regionManifests = dataManifest.getRegionManifestsList();
-
-    // Remove the region manifests. Everything is now in the data-manifest.
-    // The delete operation is "relaxed", unless we get an exception we keep going.
-    // The extra files in the snapshot directory will not give any problem,
-    // since they have the same content as the data manifest, and even by re-reading
-    // them we will get the same information.
-    if (v1Regions != null && v1Regions.size() > 0) {
-      for (SnapshotRegionManifest regionManifest: v1Regions) {
-        SnapshotManifestV1.deleteRegionManifest(fs, workingDir, regionManifest);
-      }
-    }
-    if (v2Regions != null && v2Regions.size() > 0) {
-      for (SnapshotRegionManifest regionManifest: v2Regions) {
-        SnapshotManifestV2.deleteRegionManifest(fs, workingDir, regionManifest);
-      }
-    }
-  }
-
   /*
    * Write the SnapshotDataManifest file
    */
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSTableDescriptors.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSTableDescriptors.java
deleted file mode 100644
index e1bc189e3f..0000000000
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSTableDescriptors.java
+++ /dev/null
@@ -1,802 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.hadoop.hbase.util;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import edu.umd.cs.findbugs.annotations.Nullable;
-import org.apache.commons.lang3.NotImplementedException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FSDataInputStream;
-import org.apache.hadoop.fs.FSDataOutputStream;
-import org.apache.hadoop.fs.FileStatus;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.fs.PathFilter;
-import org.apache.yetus.audience.InterfaceAudience;
-import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
-import org.apache.hadoop.hbase.client.TableDescriptor;
-import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
-import org.apache.hadoop.hbase.Coprocessor;
-import org.apache.hadoop.hbase.exceptions.DeserializationException;
-import org.apache.hadoop.hbase.HConstants;
-import org.apache.hadoop.hbase.regionserver.BloomType;
-import org.apache.hadoop.hbase.shaded.com.google.common.annotations.VisibleForTesting;
-import org.apache.hadoop.hbase.shaded.com.google.common.primitives.Ints;
-import org.apache.hadoop.hbase.TableDescriptors;
-import org.apache.hadoop.hbase.TableInfoMissingException;
-import org.apache.hadoop.hbase.TableName;
-
-/**
- * Implementation of {@link TableDescriptors} that reads descriptors from the
- * passed filesystem.  It expects descriptors to be in a file in the
- * {@link #TABLEINFO_DIR} subdir of the table's directory in FS.  Can be read-only
- *  -- i.e. does not modify the filesystem or can be read and write.
- *
- * 

Also has utility for keeping up the table descriptors tableinfo file. - * The table schema file is kept in the {@link #TABLEINFO_DIR} subdir - * of the table directory in the filesystem. - * It has a {@link #TABLEINFO_FILE_PREFIX} and then a suffix that is the - * edit sequenceid: e.g. .tableinfo.0000000003. This sequenceid - * is always increasing. It starts at zero. The table schema file with the - * highest sequenceid has the most recent schema edit. Usually there is one file - * only, the most recent but there may be short periods where there are more - * than one file. Old files are eventually cleaned. Presumption is that there - * will not be lots of concurrent clients making table schema edits. If so, - * the below needs a bit of a reworking and perhaps some supporting api in hdfs. - */ -@InterfaceAudience.Private -public class FSTableDescriptors implements TableDescriptors { - private static final Log LOG = LogFactory.getLog(FSTableDescriptors.class); - private final FileSystem fs; - private final Path rootdir; - private final boolean fsreadonly; - private volatile boolean usecache; - private volatile boolean fsvisited; - - @VisibleForTesting - long cachehits = 0; - @VisibleForTesting - long invocations = 0; - - /** - * The file name prefix used to store HTD in HDFS - */ - static final String TABLEINFO_FILE_PREFIX = ".tableinfo"; - static final String TABLEINFO_DIR = ".tabledesc"; - static final String TMP_DIR = ".tmp"; - - // This cache does not age out the old stuff. Thinking is that the amount - // of data we keep up in here is so small, no need to do occasional purge. - // TODO. - private final Map cache = new ConcurrentHashMap<>(); - - /** - * Table descriptor for hbase:meta catalog table - */ - private final TableDescriptor metaTableDescriptor; - - /** - * Construct a FSTableDescriptors instance using the hbase root dir of the given - * conf and the filesystem where that root dir lives. - * This instance can do write operations (is not read only). - */ - public FSTableDescriptors(final Configuration conf) throws IOException { - this(conf, FSUtils.getCurrentFileSystem(conf), FSUtils.getRootDir(conf)); - } - - public FSTableDescriptors(final Configuration conf, final FileSystem fs, final Path rootdir) - throws IOException { - this(conf, fs, rootdir, false, true); - } - - /** - * @param fsreadonly True if we are read-only when it comes to filesystem - * operations; i.e. on remove, we do not do delete in fs. - */ - public FSTableDescriptors(final Configuration conf, final FileSystem fs, - final Path rootdir, final boolean fsreadonly, final boolean usecache) throws IOException { - this(conf, fs, rootdir, fsreadonly, usecache, null); - } - - /** - * @param fsreadonly True if we are read-only when it comes to filesystem - * operations; i.e. on remove, we do not do delete in fs. - * @param metaObserver Used by HMaster. It need to modify the META_REPLICAS_NUM for meta table descriptor. - * see HMaster#finishActiveMasterInitialization - * TODO: This is a workaround. Should remove this ugly code... - */ - public FSTableDescriptors(final Configuration conf, final FileSystem fs, - final Path rootdir, final boolean fsreadonly, final boolean usecache, - Function metaObserver) throws IOException { - this.fs = fs; - this.rootdir = rootdir; - this.fsreadonly = fsreadonly; - this.usecache = usecache; - this.metaTableDescriptor = metaObserver == null ? createMetaTableDescriptor(conf) - : metaObserver.apply(createMetaTableDescriptorBuilder(conf)).build(); - } - - @VisibleForTesting - public static TableDescriptorBuilder createMetaTableDescriptorBuilder(final Configuration conf) throws IOException { - // TODO We used to set CacheDataInL1 for META table. When we have BucketCache in file mode, now - // the META table data goes to File mode BC only. Test how that affect the system. If too much, - // we have to rethink about adding back the setCacheDataInL1 for META table CFs. - return TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME) - .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.CATALOG_FAMILY) - .setMaxVersions(conf.getInt(HConstants.HBASE_META_VERSIONS, - HConstants.DEFAULT_HBASE_META_VERSIONS)) - .setInMemory(true) - .setBlocksize(conf.getInt(HConstants.HBASE_META_BLOCK_SIZE, - HConstants.DEFAULT_HBASE_META_BLOCK_SIZE)) - .setScope(HConstants.REPLICATION_SCOPE_LOCAL) - // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. - .setBloomFilterType(BloomType.NONE) - .build()) - .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.REPLICATION_BARRIER_FAMILY) - .setMaxVersions(conf.getInt(HConstants.HBASE_META_VERSIONS, - HConstants.DEFAULT_HBASE_META_VERSIONS)) - .setInMemory(true) - .setBlocksize(conf.getInt(HConstants.HBASE_META_BLOCK_SIZE, - HConstants.DEFAULT_HBASE_META_BLOCK_SIZE)) - .setScope(HConstants.REPLICATION_SCOPE_LOCAL) - // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. - .setBloomFilterType(BloomType.NONE) - .build()) - .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.REPLICATION_POSITION_FAMILY) - .setMaxVersions(conf.getInt(HConstants.HBASE_META_VERSIONS, - HConstants.DEFAULT_HBASE_META_VERSIONS)) - .setInMemory(true) - .setBlocksize(conf.getInt(HConstants.HBASE_META_BLOCK_SIZE, - HConstants.DEFAULT_HBASE_META_BLOCK_SIZE)) - .setScope(HConstants.REPLICATION_SCOPE_LOCAL) - // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. - .setBloomFilterType(BloomType.NONE) - .build()) - .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.REPLICATION_META_FAMILY) - .setMaxVersions(conf.getInt(HConstants.HBASE_META_VERSIONS, - HConstants.DEFAULT_HBASE_META_VERSIONS)) - .setInMemory(true) - .setBlocksize(conf.getInt(HConstants.HBASE_META_BLOCK_SIZE, - HConstants.DEFAULT_HBASE_META_BLOCK_SIZE)) - .setScope(HConstants.REPLICATION_SCOPE_LOCAL) - // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. - .setBloomFilterType(BloomType.NONE) - .build()) - .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(HConstants.TABLE_FAMILY) - // Ten is arbitrary number. Keep versions to help debugging. - .setMaxVersions(10) - .setInMemory(true) - .setBlocksize(8 * 1024) - .setScope(HConstants.REPLICATION_SCOPE_LOCAL) - // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. - .setBloomFilterType(BloomType.NONE) - .build()) - .addCoprocessor("org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint", - null, Coprocessor.PRIORITY_SYSTEM, null); - } - - @VisibleForTesting - public static TableDescriptor createMetaTableDescriptor(final Configuration conf) - throws IOException { - return createMetaTableDescriptorBuilder(conf).build(); - } - - @Override - public void setCacheOn() throws IOException { - this.cache.clear(); - this.usecache = true; - } - - @Override - public void setCacheOff() throws IOException { - this.usecache = false; - this.cache.clear(); - } - - @VisibleForTesting - public boolean isUsecache() { - return this.usecache; - } - - /** - * Get the current table descriptor for the given table, or null if none exists. - * - * Uses a local cache of the descriptor but still checks the filesystem on each call - * to see if a newer file has been created since the cached one was read. - */ - @Override - @Nullable - public TableDescriptor get(final TableName tablename) - throws IOException { - invocations++; - if (TableName.META_TABLE_NAME.equals(tablename)) { - cachehits++; - return metaTableDescriptor; - } - // hbase:meta is already handled. If some one tries to get the descriptor for - // .logs, .oldlogs or .corrupt throw an exception. - if (HConstants.HBASE_NON_USER_TABLE_DIRS.contains(tablename.getNameAsString())) { - throw new IOException("No descriptor found for non table = " + tablename); - } - - if (usecache) { - // Look in cache of descriptors. - TableDescriptor cachedtdm = this.cache.get(tablename); - if (cachedtdm != null) { - cachehits++; - return cachedtdm; - } - } - TableDescriptor tdmt = null; - try { - tdmt = getTableDescriptorFromFs(fs, rootdir, tablename); - } catch (NullPointerException e) { - LOG.debug("Exception during readTableDecriptor. Current table name = " - + tablename, e); - } catch (TableInfoMissingException e) { - // ignore. This is regular operation - } catch (IOException ioe) { - LOG.debug("Exception during readTableDecriptor. Current table name = " - + tablename, ioe); - } - // last HTD written wins - if (usecache && tdmt != null) { - this.cache.put(tablename, tdmt); - } - - return tdmt; - } - - /** - * Returns a map from table name to table descriptor for all tables. - */ - @Override - public Map getAllDescriptors() - throws IOException { - Map tds = new TreeMap<>(); - - if (fsvisited && usecache) { - for (Map.Entry entry: this.cache.entrySet()) { - tds.put(entry.getKey().toString(), entry.getValue()); - } - // add hbase:meta to the response - tds.put(this.metaTableDescriptor.getTableName().getNameAsString(), metaTableDescriptor); - } else { - LOG.debug("Fetching table descriptors from the filesystem."); - boolean allvisited = true; - for (Path d : FSUtils.getTableDirs(fs, rootdir)) { - TableDescriptor htd = null; - try { - htd = get(FSUtils.getTableName(d)); - } catch (FileNotFoundException fnfe) { - // inability of retrieving one HTD shouldn't stop getting the remaining - LOG.warn("Trouble retrieving htd", fnfe); - } - if (htd == null) { - allvisited = false; - continue; - } else { - tds.put(htd.getTableName().getNameAsString(), htd); - } - fsvisited = allvisited; - } - } - return tds; - } - - /** - * Returns a map from table name to table descriptor for all tables. - */ - @Override - public Map getAll() throws IOException { - Map htds = new TreeMap<>(); - Map allDescriptors = getAllDescriptors(); - for (Map.Entry entry : allDescriptors - .entrySet()) { - htds.put(entry.getKey(), entry.getValue()); - } - return htds; - } - - /** - * Find descriptors by namespace. - * @see #get(org.apache.hadoop.hbase.TableName) - */ - @Override - public Map getByNamespace(String name) - throws IOException { - Map htds = new TreeMap<>(); - List tableDirs = - FSUtils.getLocalTableDirs(fs, FSUtils.getNamespaceDir(rootdir, name)); - for (Path d: tableDirs) { - TableDescriptor htd = null; - try { - htd = get(FSUtils.getTableName(d)); - } catch (FileNotFoundException fnfe) { - // inability of retrieving one HTD shouldn't stop getting the remaining - LOG.warn("Trouble retrieving htd", fnfe); - } - if (htd == null) continue; - htds.put(FSUtils.getTableName(d).getNameAsString(), htd); - } - return htds; - } - - /** - * Adds (or updates) the table descriptor to the FileSystem - * and updates the local cache with it. - */ - @Override - public void add(TableDescriptor htd) throws IOException { - if (fsreadonly) { - throw new NotImplementedException("Cannot add a table descriptor - in read only mode"); - } - TableName tableName = htd.getTableName(); - if (TableName.META_TABLE_NAME.equals(tableName)) { - throw new NotImplementedException(HConstants.NOT_IMPLEMENTED); - } - if (HConstants.HBASE_NON_USER_TABLE_DIRS.contains(tableName.getNameAsString())) { - throw new NotImplementedException( - "Cannot add a table descriptor for a reserved subdirectory name: " - + htd.getTableName().getNameAsString()); - } - updateTableDescriptor(htd); - } - - /** - * Removes the table descriptor from the local cache and returns it. - * If not in read only mode, it also deletes the entire table directory(!) - * from the FileSystem. - */ - @Override - public TableDescriptor remove(final TableName tablename) - throws IOException { - if (fsreadonly) { - throw new NotImplementedException("Cannot remove a table descriptor - in read only mode"); - } - Path tabledir = getTableDir(tablename); - if (this.fs.exists(tabledir)) { - if (!this.fs.delete(tabledir, true)) { - throw new IOException("Failed delete of " + tabledir.toString()); - } - } - TableDescriptor descriptor = this.cache.remove(tablename); - return descriptor; - } - - /** - * Checks if a current table info file exists for the given table - * - * @param tableName name of table - * @return true if exists - * @throws IOException - */ - public boolean isTableInfoExists(TableName tableName) throws IOException { - return getTableInfoPath(tableName) != null; - } - - /** - * Find the most current table info file for the given table in the hbase root directory. - * @return The file status of the current table info file or null if it does not exist - */ - private FileStatus getTableInfoPath(final TableName tableName) throws IOException { - Path tableDir = getTableDir(tableName); - return getTableInfoPath(tableDir); - } - - private FileStatus getTableInfoPath(Path tableDir) - throws IOException { - return getTableInfoPath(fs, tableDir, !fsreadonly); - } - - /** - * Find the most current table info file for the table located in the given table directory. - * - * Looks within the {@link #TABLEINFO_DIR} subdirectory of the given directory for any table info - * files and takes the 'current' one - meaning the one with the highest sequence number if present - * or no sequence number at all if none exist (for backward compatibility from before there - * were sequence numbers). - * - * @return The file status of the current table info file or null if it does not exist - * @throws IOException - */ - public static FileStatus getTableInfoPath(FileSystem fs, Path tableDir) - throws IOException { - return getTableInfoPath(fs, tableDir, false); - } - - /** - * Find the most current table info file for the table in the given table directory. - * - * Looks within the {@link #TABLEINFO_DIR} subdirectory of the given directory for any table info - * files and takes the 'current' one - meaning the one with the highest sequence number if - * present or no sequence number at all if none exist (for backward compatibility from before - * there were sequence numbers). - * If there are multiple table info files found and removeOldFiles is true it also deletes the - * older files. - * - * @return The file status of the current table info file or null if none exist - * @throws IOException - */ - private static FileStatus getTableInfoPath(FileSystem fs, Path tableDir, boolean removeOldFiles) - throws IOException { - Path tableInfoDir = new Path(tableDir, TABLEINFO_DIR); - return getCurrentTableInfoStatus(fs, tableInfoDir, removeOldFiles); - } - - /** - * Find the most current table info file in the given directory - * - * Looks within the given directory for any table info files - * and takes the 'current' one - meaning the one with the highest sequence number if present - * or no sequence number at all if none exist (for backward compatibility from before there - * were sequence numbers). - * If there are multiple possible files found - * and the we're not in read only mode it also deletes the older files. - * - * @return The file status of the current table info file or null if it does not exist - * @throws IOException - */ - // only visible for FSTableDescriptorMigrationToSubdir, can be removed with that - static FileStatus getCurrentTableInfoStatus(FileSystem fs, Path dir, boolean removeOldFiles) - throws IOException { - FileStatus [] status = FSUtils.listStatus(fs, dir, TABLEINFO_PATHFILTER); - if (status == null || status.length < 1) return null; - FileStatus mostCurrent = null; - for (FileStatus file : status) { - if (mostCurrent == null || TABLEINFO_FILESTATUS_COMPARATOR.compare(file, mostCurrent) < 0) { - mostCurrent = file; - } - } - if (removeOldFiles && status.length > 1) { - // Clean away old versions - for (FileStatus file : status) { - Path path = file.getPath(); - if (file != mostCurrent) { - if (!fs.delete(file.getPath(), false)) { - LOG.warn("Failed cleanup of " + path); - } else { - LOG.debug("Cleaned up old tableinfo file " + path); - } - } - } - } - return mostCurrent; - } - - /** - * Compare {@link FileStatus} instances by {@link Path#getName()}. Returns in - * reverse order. - */ - @VisibleForTesting - static final Comparator TABLEINFO_FILESTATUS_COMPARATOR = - new Comparator() { - @Override - public int compare(FileStatus left, FileStatus right) { - return right.compareTo(left); - }}; - - /** - * Return the table directory in HDFS - */ - @VisibleForTesting Path getTableDir(final TableName tableName) { - return FSUtils.getTableDir(rootdir, tableName); - } - - private static final PathFilter TABLEINFO_PATHFILTER = new PathFilter() { - @Override - public boolean accept(Path p) { - // Accept any file that starts with TABLEINFO_NAME - return p.getName().startsWith(TABLEINFO_FILE_PREFIX); - }}; - - /** - * Width of the sequenceid that is a suffix on a tableinfo file. - */ - @VisibleForTesting static final int WIDTH_OF_SEQUENCE_ID = 10; - - /* - * @param number Number to use as suffix. - * @return Returns zero-prefixed decimal version of passed - * number (Does absolute in case number is negative). - */ - private static String formatTableInfoSequenceId(final int number) { - byte [] b = new byte[WIDTH_OF_SEQUENCE_ID]; - int d = Math.abs(number); - for (int i = b.length - 1; i >= 0; i--) { - b[i] = (byte)((d % 10) + '0'); - d /= 10; - } - return Bytes.toString(b); - } - - /** - * Regex to eat up sequenceid suffix on a .tableinfo file. - * Use regex because may encounter oldstyle .tableinfos where there is no - * sequenceid on the end. - */ - private static final Pattern TABLEINFO_FILE_REGEX = - Pattern.compile(TABLEINFO_FILE_PREFIX + "(\\.([0-9]{" + WIDTH_OF_SEQUENCE_ID + "}))?$"); - - /** - * @param p Path to a .tableinfo file. - * @return The current editid or 0 if none found. - */ - @VisibleForTesting static int getTableInfoSequenceId(final Path p) { - if (p == null) return 0; - Matcher m = TABLEINFO_FILE_REGEX.matcher(p.getName()); - if (!m.matches()) throw new IllegalArgumentException(p.toString()); - String suffix = m.group(2); - if (suffix == null || suffix.length() <= 0) return 0; - return Integer.parseInt(m.group(2)); - } - - /** - * @param sequenceid - * @return Name of tableinfo file. - */ - @VisibleForTesting static String getTableInfoFileName(final int sequenceid) { - return TABLEINFO_FILE_PREFIX + "." + formatTableInfoSequenceId(sequenceid); - } - - /** - * Returns the latest table descriptor for the given table directly from the file system - * if it exists, bypassing the local cache. - * Returns null if it's not found. - */ - public static TableDescriptor getTableDescriptorFromFs(FileSystem fs, - Path hbaseRootDir, TableName tableName) throws IOException { - Path tableDir = FSUtils.getTableDir(hbaseRootDir, tableName); - return getTableDescriptorFromFs(fs, tableDir); - } - - /** - * Returns the latest table descriptor for the table located at the given directory - * directly from the file system if it exists. - * @throws TableInfoMissingException if there is no descriptor - */ - public static TableDescriptor getTableDescriptorFromFs(FileSystem fs, Path tableDir) - throws IOException { - FileStatus status = getTableInfoPath(fs, tableDir, false); - if (status == null) { - throw new TableInfoMissingException("No table descriptor file under " + tableDir); - } - return readTableDescriptor(fs, status); - } - - private static TableDescriptor readTableDescriptor(FileSystem fs, FileStatus status) - throws IOException { - int len = Ints.checkedCast(status.getLen()); - byte [] content = new byte[len]; - FSDataInputStream fsDataInputStream = fs.open(status.getPath()); - try { - fsDataInputStream.readFully(content); - } finally { - fsDataInputStream.close(); - } - TableDescriptor htd = null; - try { - htd = TableDescriptorBuilder.parseFrom(content); - } catch (DeserializationException e) { - throw new IOException("content=" + Bytes.toShort(content), e); - } - return htd; - } - - /** - * Update table descriptor on the file system - * @throws IOException Thrown if failed update. - * @throws NotImplementedException if in read only mode - */ - @VisibleForTesting Path updateTableDescriptor(TableDescriptor td) - throws IOException { - if (fsreadonly) { - throw new NotImplementedException("Cannot update a table descriptor - in read only mode"); - } - TableName tableName = td.getTableName(); - Path tableDir = getTableDir(tableName); - Path p = writeTableDescriptor(fs, td, tableDir, getTableInfoPath(tableDir)); - if (p == null) throw new IOException("Failed update"); - LOG.info("Updated tableinfo=" + p); - if (usecache) { - this.cache.put(td.getTableName(), td); - } - return p; - } - - /** - * Deletes all the table descriptor files from the file system. - * Used in unit tests only. - * @throws NotImplementedException if in read only mode - */ - public void deleteTableDescriptorIfExists(TableName tableName) throws IOException { - if (fsreadonly) { - throw new NotImplementedException("Cannot delete a table descriptor - in read only mode"); - } - - Path tableDir = getTableDir(tableName); - Path tableInfoDir = new Path(tableDir, TABLEINFO_DIR); - deleteTableDescriptorFiles(fs, tableInfoDir, Integer.MAX_VALUE); - } - - /** - * Deletes files matching the table info file pattern within the given directory - * whose sequenceId is at most the given max sequenceId. - */ - private static void deleteTableDescriptorFiles(FileSystem fs, Path dir, int maxSequenceId) - throws IOException { - FileStatus [] status = FSUtils.listStatus(fs, dir, TABLEINFO_PATHFILTER); - for (FileStatus file : status) { - Path path = file.getPath(); - int sequenceId = getTableInfoSequenceId(path); - if (sequenceId <= maxSequenceId) { - boolean success = FSUtils.delete(fs, path, false); - if (success) { - LOG.debug("Deleted table descriptor at " + path); - } else { - LOG.error("Failed to delete descriptor at " + path); - } - } - } - } - - /** - * Attempts to write a new table descriptor to the given table's directory. - * It first writes it to the .tmp dir then uses an atomic rename to move it into place. - * It begins at the currentSequenceId + 1 and tries 10 times to find a new sequence number - * not already in use. - * Removes the current descriptor file if passed in. - * - * @return Descriptor file or null if we failed write. - */ - private static Path writeTableDescriptor(final FileSystem fs, - final TableDescriptor htd, final Path tableDir, - final FileStatus currentDescriptorFile) - throws IOException { - // Get temporary dir into which we'll first write a file to avoid half-written file phenomenon. - // This directory is never removed to avoid removing it out from under a concurrent writer. - Path tmpTableDir = new Path(tableDir, TMP_DIR); - Path tableInfoDir = new Path(tableDir, TABLEINFO_DIR); - - // What is current sequenceid? We read the current sequenceid from - // the current file. After we read it, another thread could come in and - // compete with us writing out next version of file. The below retries - // should help in this case some but its hard to do guarantees in face of - // concurrent schema edits. - int currentSequenceId = currentDescriptorFile == null ? 0 : - getTableInfoSequenceId(currentDescriptorFile.getPath()); - int newSequenceId = currentSequenceId; - - // Put arbitrary upperbound on how often we retry - int retries = 10; - int retrymax = currentSequenceId + retries; - Path tableInfoDirPath = null; - do { - newSequenceId += 1; - String filename = getTableInfoFileName(newSequenceId); - Path tempPath = new Path(tmpTableDir, filename); - if (fs.exists(tempPath)) { - LOG.debug(tempPath + " exists; retrying up to " + retries + " times"); - continue; - } - tableInfoDirPath = new Path(tableInfoDir, filename); - try { - writeTD(fs, tempPath, htd); - fs.mkdirs(tableInfoDirPath.getParent()); - if (!fs.rename(tempPath, tableInfoDirPath)) { - throw new IOException("Failed rename of " + tempPath + " to " + tableInfoDirPath); - } - LOG.debug("Wrote descriptor into: " + tableInfoDirPath); - } catch (IOException ioe) { - // Presume clash of names or something; go around again. - LOG.debug("Failed write and/or rename; retrying", ioe); - if (!FSUtils.deleteDirectory(fs, tempPath)) { - LOG.warn("Failed cleanup of " + tempPath); - } - tableInfoDirPath = null; - continue; - } - break; - } while (newSequenceId < retrymax); - if (tableInfoDirPath != null) { - // if we succeeded, remove old table info files. - deleteTableDescriptorFiles(fs, tableInfoDir, newSequenceId - 1); - } - return tableInfoDirPath; - } - - private static void writeTD(final FileSystem fs, final Path p, final TableDescriptor htd) - throws IOException { - FSDataOutputStream out = fs.create(p, false); - try { - // We used to write this file out as a serialized HTD Writable followed by two '\n's and then - // the toString version of HTD. Now we just write out the pb serialization. - out.write(TableDescriptorBuilder.toByteArray(htd)); - } finally { - out.close(); - } - } - - /** - * Create new TableDescriptor in HDFS. Happens when we are creating table. - * Used by tests. - * @return True if we successfully created file. - */ - public boolean createTableDescriptor(TableDescriptor htd) throws IOException { - return createTableDescriptor(htd, false); - } - - /** - * Create new TableDescriptor in HDFS. Happens when we are creating table. If - * forceCreation is true then even if previous table descriptor is present it - * will be overwritten - * - * @return True if we successfully created file. - */ - public boolean createTableDescriptor(TableDescriptor htd, boolean forceCreation) - throws IOException { - Path tableDir = getTableDir(htd.getTableName()); - return createTableDescriptorForTableDirectory(tableDir, htd, forceCreation); - } - - /** - * Create a new TableDescriptor in HDFS in the specified table directory. Happens when we create - * a new table or snapshot a table. - * @param tableDir table directory under which we should write the file - * @param htd description of the table to write - * @param forceCreation if true,then even if previous table descriptor is present it will - * be overwritten - * @return true if the we successfully created the file, false if the file - * already exists and we weren't forcing the descriptor creation. - * @throws IOException if a filesystem error occurs - */ - public boolean createTableDescriptorForTableDirectory(Path tableDir, - TableDescriptor htd, boolean forceCreation) throws IOException { - if (fsreadonly) { - throw new NotImplementedException("Cannot create a table descriptor - in read only mode"); - } - FileStatus status = getTableInfoPath(fs, tableDir); - if (status != null) { - LOG.debug("Current tableInfoPath = " + status.getPath()); - if (!forceCreation) { - if (fs.exists(status.getPath()) && status.getLen() > 0) { - if (readTableDescriptor(fs, status).equals(htd)) { - LOG.debug("TableInfo already exists.. Skipping creation"); - return false; - } - } - } - } - Path p = writeTableDescriptor(fs, htd, tableDir, status); - return p != null; - } - -} - diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java index 81fcaf201f..9c2f065f38 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java @@ -1007,8 +1007,7 @@ public abstract class FSUtils extends CommonFSUtils { } /** - * Given a particular table dir, return all the regiondirs inside it, excluding files such as - * .tableinfo + * Given a particular table dir, return all the regiondirs inside it. * @param fs A file system for the Path * @param tableDir Path to a specific table directory <hbase.rootdir>/<tabledir> * @return List of paths to valid region directories in table dir. -- 2.11.0 (Apple Git-81)