Skip to content

Commit db92976

Browse files
committed
[Iceberg]Support renaming table on hive file catalog
1 parent 652026b commit db92976

File tree

3 files changed

+643
-16
lines changed

3 files changed

+643
-16
lines changed

presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/file/FileHiveMetastore.java

+75-10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package com.facebook.presto.hive.metastore.file;
1515

1616
import com.facebook.airlift.json.JsonCodec;
17+
import com.facebook.airlift.log.Logger;
1718
import com.facebook.presto.common.predicate.Domain;
1819
import com.facebook.presto.common.type.Type;
1920
import com.facebook.presto.hive.HdfsContext;
@@ -63,6 +64,7 @@
6364
import org.apache.hadoop.fs.FSDataInputStream;
6465
import org.apache.hadoop.fs.FileStatus;
6566
import org.apache.hadoop.fs.FileSystem;
67+
import org.apache.hadoop.fs.FileUtil;
6668
import org.apache.hadoop.fs.Path;
6769

6870
import javax.annotation.concurrent.ThreadSafe;
@@ -99,7 +101,6 @@
99101
import static com.facebook.presto.hive.metastore.MetastoreUtil.getHiveBasicStatistics;
100102
import static com.facebook.presto.hive.metastore.MetastoreUtil.getPartitionNamesWithEmptyVersion;
101103
import static com.facebook.presto.hive.metastore.MetastoreUtil.isIcebergTable;
102-
import static com.facebook.presto.hive.metastore.MetastoreUtil.isIcebergView;
103104
import static com.facebook.presto.hive.metastore.MetastoreUtil.makePartName;
104105
import static com.facebook.presto.hive.metastore.MetastoreUtil.toPartitionValues;
105106
import static com.facebook.presto.hive.metastore.MetastoreUtil.updateStatisticsParameters;
@@ -117,6 +118,7 @@
117118
import static com.google.common.base.MoreObjects.toStringHelper;
118119
import static com.google.common.base.Preconditions.checkArgument;
119120
import static com.google.common.collect.ImmutableList.toImmutableList;
121+
import static java.lang.String.format;
120122
import static java.util.Collections.emptyList;
121123
import static java.util.Objects.requireNonNull;
122124
import static java.util.UUID.randomUUID;
@@ -128,6 +130,7 @@
128130
public class FileHiveMetastore
129131
implements ExtendedHiveMetastore
130132
{
133+
private static final Logger LOG = Logger.get(FileHiveMetastore.class);
131134
private static final String PUBLIC_ROLE_NAME = "public";
132135
private static final String ADMIN_ROLE_NAME = "admin";
133136
private static final String PRESTO_SCHEMA_FILE_NAME = ".prestoSchema";
@@ -208,9 +211,8 @@ public synchronized void renameDatabase(MetastoreContext metastoreContext, Strin
208211
verifyDatabaseNotExists(metastoreContext, newDatabaseName);
209212

210213
try {
211-
if (!metadataFileSystem.rename(getDatabaseMetadataDirectory(databaseName), getDatabaseMetadataDirectory(newDatabaseName))) {
212-
throw new PrestoException(HIVE_METASTORE_ERROR, "Could not rename database metadata directory");
213-
}
214+
renamePath(getDatabaseMetadataDirectory(databaseName), getDatabaseMetadataDirectory(newDatabaseName),
215+
"Could not rename database metadata directory");
214216
}
215217
catch (IOException e) {
216218
throw new PrestoException(HIVE_METASTORE_ERROR, e);
@@ -514,22 +516,85 @@ public synchronized MetastoreOperationResult renameTable(MetastoreContext metast
514516
requireNonNull(newTableName, "newTableName is null");
515517
Table table = getRequiredTable(metastoreContext, databaseName, tableName);
516518
getRequiredDatabase(metastoreContext, newDatabaseName);
517-
if (isIcebergTable(table) && !isIcebergView(table)) {
518-
throw new PrestoException(NOT_SUPPORTED, "Rename not supported for Iceberg tables");
519-
}
520519
// verify new table does not exist
521520
verifyTableNotExists(metastoreContext, newDatabaseName, newTableName);
522521

522+
Path metadataDirectory = getTableMetadataDirectory(databaseName, tableName);
523+
Path newMetadataDirectory = getTableMetadataDirectory(newDatabaseName, newTableName);
524+
525+
if (isIcebergTable(table)) {
526+
renameIcebergTable(metadataDirectory, newMetadataDirectory);
527+
}
528+
else {
529+
renameTable(metadataDirectory, newMetadataDirectory);
530+
}
531+
532+
return EMPTY_RESULT;
533+
}
534+
535+
private void renameIcebergTable(Path originalMetadataDirectory, Path newMetadataDirectory)
536+
{
537+
Optional<Runnable> rollbackAction = Optional.empty();
523538
try {
524-
if (!metadataFileSystem.rename(getTableMetadataDirectory(databaseName, tableName), getTableMetadataDirectory(newDatabaseName, newTableName))) {
525-
throw new PrestoException(HIVE_METASTORE_ERROR, "Could not rename table directory");
539+
// If the directory `.prestoPermissions` exists, copy it to the new table metadata directory
540+
Path originTablePermissionDir = new Path(originalMetadataDirectory, PRESTO_PERMISSIONS_DIRECTORY_NAME);
541+
Path newTablePermissionDir = new Path(newMetadataDirectory, PRESTO_PERMISSIONS_DIRECTORY_NAME);
542+
if (metadataFileSystem.exists(originTablePermissionDir)) {
543+
if (!FileUtil.copy(metadataFileSystem, originTablePermissionDir,
544+
metadataFileSystem, newTablePermissionDir, false, metadataFileSystem.getConf())) {
545+
throw new IOException(format("Could not rename table. Failed to copy directory: %s to %s", originTablePermissionDir, newTablePermissionDir));
546+
}
547+
else {
548+
rollbackAction = Optional.of(() -> {
549+
try {
550+
metadataFileSystem.delete(newTablePermissionDir, true);
551+
}
552+
catch (IOException e) {
553+
LOG.warn("Could not delete table permission directory: %s", newTablePermissionDir);
554+
}
555+
});
556+
}
557+
}
558+
559+
// Rename file `.prestoSchema` to change it to the new metadata path
560+
// This will atomically execute the table renaming behavior
561+
Path originMetadataFile = new Path(originalMetadataDirectory, PRESTO_SCHEMA_FILE_NAME);
562+
Path newMetadataFile = new Path(newMetadataDirectory, PRESTO_SCHEMA_FILE_NAME);
563+
renamePath(originMetadataFile, newMetadataFile,
564+
format("Could not rename table. Failed to rename file %s to %s", originMetadataFile, newMetadataFile));
565+
566+
// Subsequent action, delete the redundant directory `.prestoPermissions` from the original table metadata path
567+
try {
568+
metadataFileSystem.delete(new Path(originalMetadataDirectory, PRESTO_PERMISSIONS_DIRECTORY_NAME), true);
569+
}
570+
catch (IOException e) {
571+
// ignore
526572
}
527573
}
528574
catch (IOException e) {
575+
// If table renaming fails and rollback action has already been recorded, perform the rollback action to clean up junk files
576+
rollbackAction.ifPresent(Runnable::run);
529577
throw new PrestoException(HIVE_METASTORE_ERROR, e);
530578
}
579+
}
531580

532-
return EMPTY_RESULT;
581+
private void renameTable(Path originalMetadataDirectory, Path newMetadataDirectory)
582+
{
583+
try {
584+
renamePath(originalMetadataDirectory, newMetadataDirectory,
585+
format("Could not rename table. Failed to rename directory %s to %s", originalMetadataDirectory, newMetadataDirectory));
586+
}
587+
catch (IOException e) {
588+
throw new PrestoException(HIVE_METASTORE_ERROR, e);
589+
}
590+
}
591+
592+
private void renamePath(Path originalPath, Path targetPath, String errorMessage)
593+
throws IOException
594+
{
595+
if (!metadataFileSystem.rename(originalPath, targetPath)) {
596+
throw new IOException(errorMessage);
597+
}
533598
}
534599

535600
@Override

presto-iceberg/src/test/java/com/facebook/presto/iceberg/hive/TestIcebergHiveCatalogDistributedQueries.java

-6
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,4 @@ public TestIcebergHiveCatalogDistributedQueries()
2828
{
2929
super(HIVE, ImmutableMap.of("iceberg.hive-statistics-merge-strategy", Joiner.on(",").join(NUMBER_OF_DISTINCT_VALUES.name(), TOTAL_SIZE_IN_BYTES.name())));
3030
}
31-
32-
@Override
33-
public void testRenameTable()
34-
{
35-
// Rename table are not supported by hive catalog
36-
}
3731
}

0 commit comments

Comments
 (0)