-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Iceberg]Support setting warehouse data directory for Hadoop catalog #24397
base: master
Are you sure you want to change the base?
[Iceberg]Support setting warehouse data directory for Hadoop catalog #24397
Conversation
0279ea7
to
2390fb0
Compare
presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergUtil.java
Outdated
Show resolved
Hide resolved
2390fb0
to
c3c00e1
Compare
c3c00e1
to
d18cd8b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the doc! Looks good, only a few nits only of punctuation and capitalization.
d18cd8b
to
5fd6b9c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! (docs)
Pulled updated branch, new local doc build, looks good. Thanks!
Thanks @steveburnett for your suggestion, fixed! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the change. LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hantangwangd Thanks for the PR! I took a first pass and had some minor comments.
@@ -1023,6 +1040,62 @@ public void setTableProperties(ConnectorSession session, ConnectorTableHandle ta | |||
transaction.commitTransaction(); | |||
} | |||
|
|||
protected Map<String, String> populateTableProperties(ConnectorTableMetadata tableMetadata, com.facebook.presto.iceberg.FileFormat fileFormat, ConnectorSession session, CatalogType catalogType) | |||
{ | |||
ImmutableMap.Builder<String, String> propertiesBuilder = ImmutableMap.builderWithExpectedSize(5); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should we update the builder size here? I think initially when we had 5 properties it was set to 5 but I can see now we have more than 5.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I have change it to 16, which is a little bigger than current properties count. Since some more table properties will be added in the future.
presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
@Config("iceberg.catalog.warehouse.datadir") | ||
@ConfigDescription("Iceberg catalog default root data writing directory") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should we mention that it is only supported for Hadoop catalog in the ConfigDescription?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to add a check to throw an error at the server startup if this config is present in the config file when the catalog type is not Hadoop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to add a check to throw an error at the server startup if this config is present in the config file when the catalog type is not Hadoop?
I added this check in IcebergCommonModule
, but I'm not quite sure if we should throw an error or just ignore this property in non-Hadoop catalogs. Currently, iceberg.catalog.warehouse
will be just ignored instead of throw an error. Perhaps we can listen to what other reviewers are thinking @tdcmeehan @ZacBlanco @agrawalreetika @kiersten-stokes?
should we mention that it is only supported for Hadoop catalog in the ConfigDescription?
Sure, added!
@@ -52,6 +52,7 @@ public class IcebergNativeCatalogFactory | |||
private final String catalogName; | |||
protected final CatalogType catalogType; | |||
private final String catalogWarehouse; | |||
private final String catalogWarehouseDataDir; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we move this to IcebergNativeMetadata since it's only being used in that class and not in this class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IcebergNativeMetadata
already holds this field. I think this is mainly a problem with parameter passing. IcebergNativeMetadata
needs to be passed in the value of catalogWarehouseDataDir
, so we need to hold catalogWarehouseDataDir
in IcebergNativeCatalogFactory
or IcebergNativeMetaFactory
, so that we can pass the value of catalogWarehouseDataDir
to create a new IcebergNativeMetadata
when executing IcebergNativeMetadataFactory.create()
.
So I hold catalogWarehouseDir
in IcebergNativeCatalogFactory
and pass it to IcebergNativeMetadata
through IcebergNativeCatalogFactory
, because this is the way I believe the smallest changes will be made. Do you have a better way to pass catalogWarehouseDir
into IcebergNativeMetadata
?
@@ -150,6 +152,34 @@ public void testShowCreateTable() | |||
")", schemaName, getLocation(schemaName, "orders"))); | |||
} | |||
|
|||
@Test | |||
public void testTableWithSpecifiedWriteDataLocation() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like testTableWithSpecifiedWriteDataLocation
and testShowCreateTableWithSpecifiedWriteDataLocation
are the same. Can you please check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think they look the same mainly because they are both implementations which implies not supported by default in the base test class. And in the relevant subclass of Hadoop catalog, they will be overwritten with different implementation logic.
throws IOException | ||
{ | ||
String dataWriteLocation = Files.createTempDirectory("test_table_with_specified_write_data_location3").toAbsolutePath().toString(); | ||
assertQueryFails(String.format("create table test_table_with_specified_write_data_location3(a int, b varchar) with (write_data_path = '%s')", dataWriteLocation), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we attempt to create a partitioned table for this test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, done!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just have a few high level comments. At the core, I understand what we're trying to solve, but I'm not sure yet if this is the right solution. What happens when we have a table which already exists at the warehouse directory but has a data directory which doesn't align with the new datadir property? Should we respect the property or the table in the case of an insert? This could be confusing for users.
And if the table already exists and doesn't doesn't have a metadata folder which is in a "safe" filesystem, should we error, or warn the user? Do we even have a way of knowing that a filesystem is "safe" (supports atomic renames)?
Correct me if I'm wrong, but in theory we could have already supported this use case within the iceberg connector by using SetTableProperty procedure and just setting "write.data.path" on the individual tables, right? From my understanding, all this change does is provide a default for new tables and makes it a viewable table property. I'm wondering if it might be better providing this as schema-level property that users can set, similar to how the hive connector has a schema-level "location" property. Then, we can set defaults for the data path on schema creation, but override it on a table-level if we prefer.
However, I don't believe the metadata path could be set that way since the HadoopCatalog relies on listing the warehouse metadata directories to get the schemas and tables.
Just some thoughts for discussion. I think I just want to refine our approach and make sure there isn't any ambiguous behavior from the user perspective.
icebergProperties.put("iceberg.file-format", format.name()); | ||
icebergProperties.putAll(getConnectorProperties(CatalogType.valueOf(catalogType), icebergDataDirectory)); | ||
icebergProperties.putAll(extraConnectorProperties); | ||
queryRunner.createCatalog(ICEBERG_CATALOG, "iceberg", ImmutableMap.copyOf(icebergProperties)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason to change this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we need a way to let the properties explicitly set in the test class to override the default properties set by the underlying query runner. For example, we need to explicitly specify iceberg.catalog.warehouse
in the test class.
@@ -370,6 +393,9 @@ Property Name Description | |||
``location`` Optionally specifies the file system location URI for | |||
the table. | |||
|
|||
``write_data_path`` Optionally specifies the file system location URI for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would actually prefer if we used the same property name as in iceberg to make it less confusing to users. I know we haven't followed this before but I feel like it makes more sense than what we have now. It allows for more continuity and easier for users to look up the iceberg property reference as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, I think this makes sense. Then how do you think we should handle the previous table properties?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have to do it in this PR but here's a solution I think would work for deprecation of the old names:
Inside of IcebergTableProperties
create a map of (new property name -> old property name) say, deprecatedProperties
.
Then we update all existing table properties with iceberg-equivalents to the iceberg name (if one exists).
Inside of the constructor or getTableProperties
method of IcebergTableProperties
, we take the deprecatedProperties
map and iterate over of the existing properties and if it has an entry in the deprecatedProperties
map, add a new hidden property with the old name and same parameters as the new property.
In each of the getXXX
methods, we would also need to fall back to checking for the old property name in the map. We would also need a method to add a warning to the session that the table property name is deprecated. We can leave it like that for a few releases and eventually remove the deprecated property names.
This could all be done in a separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds good. I have changed the newly added table property name to write.data.path
, which is exactly the same as Iceberg's corresponding table property name. Please take a look when available, thanks!
19b2e45
5fd6b9c
to
19b2e45
Compare
@ZacBlanco Thanks for your feedback, very glad to be able to clarify and refine the approch through discussion. Overall, I think the core point of this change is to separate the data write path and metadata path of Iceberg tables in Hadoop catalog, and provide a simpler and more convenient way for users to specify the data write path of tables. I will reply item by item below. Please let me know if you have any comments.
Undoubtedly, when inserting data, the iceberg table's table property
Do you think the above behaviors make sense?
I think we could specify the requirements for the file system where the metadata is located in the document. But I don't think Presto engine is responsible for identifying and distinguishing specific file systems and reminding users. This is the user's own responsibility, because they have a better understanding of their own usage scenarios. For example, for a considerable number of users, they do not need to consider transaction consistency issues caused by cross engine interoperability.
Firstly, for Hadoop catalog, we cannot arbitrarily set the value of Therefore, if necessary, we can add this schema-level data dir property in the future. I think it can work well with catalog-level data dir. What's your opinion? |
New release note guidelines as of last week: PR #24354 automatically adds links to this PR to the release notes. Please remove the manual PR link in the following format from the release note entries for this PR.
I have updated the Release Notes Guidelines to remove the examples of manually adding the PR link. |
Thanks for your response. I did some more thinking around this and concluded that we don't really have a consistent way of specifying location for each connector. But I think we should strive to do so. Some examples:
My thoughts are that
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the great work - I do have a concern about the additional load on CI the two new test classes might have. Please let me know your thoughts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little concerned about the impact of runtime of the CI when adding this test class and the TestIcebergSmokeOnS3Hadoop
test class. These classes take quite a bit of time to complete, so I think we should try to be prudent about adding new configurations permutations that run through the whole gamut of tests.
That being said, since the only real difference in the configuration is the warehouse default data dir, and the fact we're running on S3 I think we ought to enable just one version of this test. Either the default which operates directly on the local filesystem or this one. I would actually err towards using this class because it represents something closer to real-world use case while still exercising the Hadoop catalog.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense to enable just one version of these three test classes. And I agree with you that the new version tests on S3 are more suitable to be enabled, since they still exercising the Hadoop catalog.
I tried to ignore the original test classes, but led to a series of problems in the CI environment. Will make some further attempts. Would be great appreciate if you have any good ideas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have you tried just putting @Test(enabled = false)
at the class-level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem to work. I previously used @ignore, but it also didn't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A feasible way is to declare them as abstract classes, this works well in CI environment, see #24508. Not so sure if there is a better way.
...eberg/src/test/java/com/facebook/presto/iceberg/hadoop/TestIcebergDistributedOnS3Hadoop.java
Outdated
Show resolved
Hide resolved
.../java/com/facebook/presto/iceberg/hadoop/TestIcebergHadoopCatalogOnS3DistributedQueries.java
Outdated
Show resolved
Hide resolved
...eberg/src/test/java/com/facebook/presto/iceberg/hadoop/TestIcebergDistributedOnS3Hadoop.java
Outdated
Show resolved
Hide resolved
presto-iceberg/src/test/java/com/facebook/presto/iceberg/hadoop/TestIcebergSmokeOnS3Hadoop.java
Outdated
Show resolved
Hide resolved
presto-iceberg/src/test/java/com/facebook/presto/iceberg/hadoop/TestIcebergSmokeOnS3Hadoop.java
Outdated
Show resolved
Hide resolved
presto-iceberg/src/test/java/com/facebook/presto/iceberg/hadoop/TestIcebergSmokeOnS3Hadoop.java
Outdated
Show resolved
Hide resolved
presto-iceberg/src/test/java/com/facebook/presto/iceberg/hadoop/TestIcebergSmokeOnS3Hadoop.java
Outdated
Show resolved
Hide resolved
f3c462f
to
f08edd5
Compare
@ZacBlanco Thanks for your investigation and perspective. I think a significant portion of the current inconsistency is due to Iceberg connector with Hive catalog. In presto, its configuration is closer to Hive connector than Iceberg lib's Hive catalog, because it is a presto native implementation based on As far as I can see, in Iceberg lib, As you said, the newly added configuration property is an external process with Iceberg's own configuration, and it should only be used for Hadoop catalog. Therefore, in order to avoid the confusion with property
Do you think this makes sense? |
Thanks @steveburnett for your message. I have fixed the release note and supplemented some content to the document, please take a look when convenient. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the expanded documentation! I made a few minor revision suggestions to use imperative, to emphasize what the user should and should not do.
This approach sounds good to me |
b39e317
to
3356d39
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the quick revision! I'm glad you rephrased my suggestion for technical accuracy. Just a few minor nits of formatting and spacing, but everything looks good.
3356d39
to
93191b4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly nits. A couple questions for discussion
presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java
Outdated
Show resolved
Hide resolved
presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java
Outdated
Show resolved
Hide resolved
{ | ||
try { | ||
String writeDataLocation = table.properties().get(WRITE_DATA_LOCATION); | ||
return Optional.of(Strings.isNullOrEmpty(writeDataLocation) ? table.location() : writeDataLocation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
technically the default from the LocationProviders
class in iceberg is `table.location() + "/data"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After rechecking this part of the code, I found that this method seems unnecessary. It's OK to just use tableLocation
as before. Because when constructing the LocationProvider
later, we passed both tableLocation
and tableProperties
into it. And the LocationProvider
will find the appropriate write data location based on tableProperties
and tableLocation
.
I have refactored this part of code, please take a look when convenient, thanks.
presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergNativeMetadata.java
Outdated
Show resolved
Hide resolved
presto-iceberg/src/test/java/com/facebook/presto/iceberg/IcebergDistributedSmokeTestBase.java
Show resolved
Hide resolved
} | ||
|
||
@Test | ||
public void testPropertiesTableWithSpecifiedDataWriteLocation() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm this is getting me thinking that maybe we ought to have a test class which creates a query runner configured with all of the catalog types. Then we don't have to create new test classes which have the overhead of starting new query runners all the time.
I think this is fine for the PR, but I am concerned that we're creating a lot of overhead in testing for these different config scenarios. I think it might be worth an effort to try to consolidate to reduce the CI times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like a good idea, , I think it worth trying. And the testing scenarios of TestIcebergSystemTables
are relatively simple, make it more suitable for trying this.
" metadata_delete_after_commit = false,\n" + | ||
" metadata_previous_versions_max = 100,\n" + | ||
" metrics_max_inferred_column = 100,\n" + | ||
" \"write.data.path\" = '%s'\n" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's ok to leave for now, but I noticed adding a new table property is quite cumbersome because we have to update all of these tests which look for the exact SQL create statement. It's a bit of a burden for maintenance. Do you have any thoughts about how we might be able to make it less fragile?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we can extract a method that can verify the result of the show create table
statement, which takes the basic information, columns, and properties fo the table as parameters. All relevant tests can utilize this method, which may result in fewer changes to the test cases when adding new table property in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! (docs)
Pull updated branch, new local doc build, looks good.
ce4d9fc
to
b7206dc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates. One final question
propertiesBuilder.put(WRITE_DATA_LOCATION, writeDataLocation); | ||
} | ||
else { | ||
throw new PrestoException(NOT_SUPPORTED, "Table property write.data.path is not supported with catalog type: " + catalogType); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this actually the case? If the property is set on the table correctly it will be reflected in the location provider, right? I don't think we need to disable it for other catalogs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a good question. Enabling this table property directly on all catalogs may cause unexpected problems. For example, if we specify this property in a table on Hive file catalog, when we trying to drop the table, we would fail with the following message:
Table test_table contains Iceberg path override properties and cannot be dropped from Presto
That would lead in a lot of troubles for test on Iceberg hive catalog.
So I choose not to enable it on other catalogs for now, and will enable them after confirming that there are no issues. Do you think it's OK?
…ther than `write_data_path`
…warehouse.datadir` to `iceberg.catalog.hadoop.warehouse.datadir`
b7206dc
to
0749403
Compare
0749403
to
acf8a00
Compare
Description
This PR enable Presto Iceberg Hadoop catalog to specify an independent warehouse data directory to store table data files, in this way, we can manage metadata files on HDFS and store data files on Object Stores in a formal production environment.
See issue: #24383
Motivation and Context
Enabling Presto Iceberg to leverage the powerful capabilities of object storages
Impact
Hadoop catalog has the capability of leveraging object stores
Test Plan
iceberg.catalog.warehouse
to a local file path, andiceberg.catalog.hadoop.warehouse.datadir
to a s3 path, fully runIcebergDistributedTestBase
,IcebergDistributedSmokeTestBase
, andTestIcebergDistributedQueries
in CI testContributor checklist
Release Notes