Index: src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java (revision 1158520) +++ src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java (working copy) @@ -410,11 +410,13 @@ return tableInfoPath; } - /** + /** * Create new HTableDescriptor in HDFS. + * * @param htableDescriptor */ - public void createTableDescriptor(HTableDescriptor htableDescriptor) { + public void createTableDescriptor(HTableDescriptor htableDescriptor) + throws IOException { FSUtils.createTableDescriptor(htableDescriptor, conf); } Index: src/main/java/org/apache/hadoop/hbase/util/FSUtils.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/util/FSUtils.java (revision 1158520) +++ src/main/java/org/apache/hadoop/hbase/util/FSUtils.java (working copy) @@ -938,42 +938,76 @@ } /** - * Create new HTableDescriptor in HDFS. Happens when we are creating table. + * Create new HTableDescriptor in HDFS. Happens when we are creating table. + * + * @param htableDescriptor + * @param conf + */ + public static boolean createTableDescriptor( + HTableDescriptor htableDescriptor, Configuration conf) throws IOException { + return createTableDescriptor(htableDescriptor, conf, false); + } + /** + * Create new HTableDescriptor in HDFS. Happens when we are creating table. If + * forceCreation is true then even if previous table descriptor is present it + * will be overwritten + * * @param htableDescriptor * @param conf + * @param forceCreation */ - public static void createTableDescriptor(HTableDescriptor htableDescriptor, - Configuration conf) { - try { - FileSystem fs = getCurrentFileSystem(conf); - createTableDescriptor(fs, getRootDir(conf), htableDescriptor); - } catch(IOException ioe) { - LOG.info("IOException while trying to create tableInfo in HDFS", ioe); - } + public static boolean createTableDescriptor( + HTableDescriptor htableDescriptor, Configuration conf, + boolean forceCreation) throws IOException { + FileSystem fs = getCurrentFileSystem(conf); + return createTableDescriptor(fs, getRootDir(conf), htableDescriptor, + forceCreation); } /** + * Create new HTableDescriptor in HDFS. Happens when we are creating table. + * * @param fs * @param htableDescriptor * @param rootdir */ - public static void createTableDescriptor(FileSystem fs, - Path rootdir, HTableDescriptor htableDescriptor) { + public static boolean createTableDescriptor(FileSystem fs, Path rootdir, + HTableDescriptor htableDescriptor) throws IOException { + return createTableDescriptor(fs, rootdir, htableDescriptor, false); + } + + /** + * Create new HTableDescriptor in HDFS. Happens when we are creating table. If + * forceCreation is true then even if previous table descriptor is present it + * will be overwritten + * + * @param fs + * @param htableDescriptor + * @param rootdir + * @param forceCreation + */ + public static boolean createTableDescriptor(FileSystem fs, Path rootdir, + HTableDescriptor htableDescriptor, boolean forceCreation) + throws IOException { try { - Path tableInfoPath = - getTableInfoPath(rootdir, htableDescriptor.getNameAsString()); - LOG.info("Current tableInfoPath = " + tableInfoPath) ; - if (fs.exists(tableInfoPath) && - fs.getFileStatus(tableInfoPath).getLen() > 0) { - LOG.info("TableInfo already exists.. Skipping creation"); - return; + Path tableInfoPath = getTableInfoPath(rootdir, htableDescriptor + .getNameAsString()); + LOG.info("Current tableInfoPath = " + tableInfoPath); + if (!forceCreation) { + if (fs.exists(tableInfoPath) + && fs.getFileStatus(tableInfoPath).getLen() > 0) { + LOG.info("TableInfo already exists.. Skipping creation"); + return false; + } } - writeTableDescriptor(fs, htableDescriptor, - getTablePath(rootdir, htableDescriptor.getNameAsString())); - } catch(IOException ioe) { - LOG.info("IOException while trying to create tableInfo in HDFS", ioe); + writeTableDescriptor(fs, htableDescriptor, getTablePath(rootdir, + htableDescriptor.getNameAsString()), forceCreation); + } catch (IOException ioe) { + LOG.error("IOException while trying to create tableInfo in HDFS", ioe); + throw ioe; } + return true; } /** @@ -990,25 +1024,34 @@ /** * Called when we are creating a table to write out the tables' descriptor. + * * @param fs * @param hTableDescriptor * @param tableDir * @throws IOException */ private static void writeTableDescriptor(FileSystem fs, - HTableDescriptor hTableDescriptor, Path tableDir) - throws IOException { + HTableDescriptor hTableDescriptor, Path tableDir, boolean forceCreation) + throws IOException { // 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, + // 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. Path tableInfoPath = new Path(tableDir, HConstants.TABLEINFO_NAME); - Path tmpPath = new Path(new Path(tableDir,".tmp"), HConstants.TABLEINFO_NAME); + Path tmpPath = new Path(new Path(tableDir, ".tmp"), + HConstants.TABLEINFO_NAME); LOG.info("TableInfoPath = " + tableInfoPath + " tmpPath = " + tmpPath); writeHTD(fs, tmpPath, hTableDescriptor); + if (forceCreation) { + if (!fs.delete(tableInfoPath, false)) { + String errMsg = "Unable to delete " + tableInfoPath + + " while forcefully writing the table descriptor."; + throw new IOException(errMsg); + } + } if (!fs.rename(tmpPath, tableInfoPath)) { - throw new IOException("Unable to rename " + tmpPath + " to " + - tableInfoPath); + String errMsg = "Unable to rename " + tmpPath + " to " + tableInfoPath; + throw new IOException(errMsg); } else { LOG.info("TableDescriptor stored. TableInfoPath = " + tableInfoPath); } Index: src/test/java/org/apache/hadoop/hbase/TestFSTableDescriptorForceCreation.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/TestFSTableDescriptorForceCreation.java (revision 0) +++ src/test/java/org/apache/hadoop/hbase/TestFSTableDescriptorForceCreation.java (revision 0) @@ -0,0 +1,84 @@ +/** + * Copyright 2011 The Apache Software Foundation + * + * 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 static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hbase.util.FSTableDescriptors; +import org.apache.hadoop.hbase.util.FSUtils; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestFSTableDescriptorForceCreation { + private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); + + @BeforeClass + public static void setUpCluster() throws Exception { + UTIL.startMiniDFSCluster(1); + } + + @AfterClass + public static void shutDownCluster() throws Exception { + UTIL.shutdownMiniDFSCluster(); + } + + @Test + public void testShouldCreateNewTableDescriptorIfForceFulCreationIsFalse() + throws IOException { + final String name = "newTable2"; + FileSystem fs = FileSystem.get(UTIL.getConfiguration()); + Path rootdir = new Path(fs.getWorkingDirectory(), name); + HTableDescriptor htd = new HTableDescriptor(name); + assertTrue("Should create new table descriptor", FSUtils + .createTableDescriptor(fs, rootdir, htd, false)); + } + + @Test + public void testShouldNotCreateTheSameTableDescriptorIfForceFulCreationIsFalse() + throws IOException { + final String name = "testAlreadyExists"; + FileSystem fs = FileSystem.get(UTIL.getConfiguration()); + // Cleanup old tests if any detrius laying around. + Path rootdir = new Path(fs.getWorkingDirectory(), name); + TableDescriptors htds = new FSTableDescriptors(fs, rootdir); + HTableDescriptor htd = new HTableDescriptor(name); + htds.add(htd); + assertFalse("Should not create new table descriptor", FSUtils + .createTableDescriptor(fs, rootdir, htd, false)); + } + + @Test + public void testShouldAllowForceFulCreationOfAlreadyExistingTableDescriptor() + throws Exception { + final String name = "createNewTableNew2"; + FileSystem fs = FileSystem.get(UTIL.getConfiguration()); + Path rootdir = new Path(fs.getWorkingDirectory(), name); + HTableDescriptor htd = new HTableDescriptor(name); + FSUtils.createTableDescriptor(fs, rootdir, htd, false); + assertTrue("Should create new table descriptor", FSUtils + .createTableDescriptor(fs, rootdir, htd, true)); + } +}