-
Notifications
You must be signed in to change notification settings - Fork 2.5k
[HUDI-3654] Preparations for hudi metastore. #5572
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| /* | ||
| * 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.hudi.common.config; | ||
|
|
||
| import javax.annotation.concurrent.Immutable; | ||
| import java.util.Properties; | ||
|
|
||
| /** | ||
| * Configurations used by the HUDI Metastore. | ||
| */ | ||
| @Immutable | ||
| @ConfigClassProperty(name = "Metastore Configs", | ||
| groupName = ConfigGroups.Names.WRITE_CLIENT, | ||
| description = "Configurations used by the Hudi Metastore.") | ||
| public class HoodieMetastoreConfig extends HoodieConfig { | ||
|
|
||
| public static final String METASTORE_PREFIX = "hoodie.metastore"; | ||
|
|
||
| public static final ConfigProperty<Boolean> METASTORE_ENABLE = ConfigProperty | ||
| .key(METASTORE_PREFIX + ".enable") | ||
| .defaultValue(false) | ||
| .withDocumentation("Use metastore server to store hoodie table metadata"); | ||
|
|
||
| public static final ConfigProperty<String> METASTORE_URLS = ConfigProperty | ||
| .key(METASTORE_PREFIX + ".uris") | ||
| .defaultValue("thrift://localhost:9090") | ||
| .withDocumentation("Metastore server uris"); | ||
|
|
||
| public static final ConfigProperty<Integer> METASTORE_CONNECTION_RETRIES = ConfigProperty | ||
| .key(METASTORE_PREFIX + ".connect.retries") | ||
| .defaultValue(3) | ||
| .withDocumentation("Number of retries while opening a connection to metastore"); | ||
|
|
||
| public static final ConfigProperty<Integer> METASTORE_CONNECTION_RETRY_DELAY = ConfigProperty | ||
| .key(METASTORE_PREFIX + ".connect.retry.delay") | ||
| .defaultValue(1) | ||
| .withDocumentation("Number of seconds for the client to wait between consecutive connection attempts"); | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we also need the parameter 'connectionlifetimeinmillis' to control MetaStore Client socket lifetime. WDYT
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good suggestions. Will add it in the following PR #5064 |
||
| public static HoodieMetastoreConfig.Builder newBuilder() { | ||
| return new HoodieMetastoreConfig.Builder(); | ||
| } | ||
|
|
||
| public boolean enableMetastore() { | ||
| return getBoolean(METASTORE_ENABLE); | ||
| } | ||
|
|
||
| public String getMetastoreUris() { | ||
| return getStringOrDefault(METASTORE_URLS); | ||
| } | ||
|
|
||
| public int getConnectionRetryLimit() { | ||
| return getIntOrDefault(METASTORE_CONNECTION_RETRIES); | ||
| } | ||
|
|
||
| public int getConnectionRetryDelay() { | ||
| return getIntOrDefault(METASTORE_CONNECTION_RETRY_DELAY); | ||
| } | ||
|
|
||
| public static class Builder { | ||
| private final HoodieMetastoreConfig config = new HoodieMetastoreConfig(); | ||
|
|
||
| public Builder fromProperties(Properties props) { | ||
| this.config.getProps().putAll(props); | ||
| return this; | ||
| } | ||
|
|
||
| public Builder setUris(String uris) { | ||
| config.setValue(METASTORE_URLS, uris); | ||
| return this; | ||
| } | ||
|
|
||
| public HoodieMetastoreConfig build() { | ||
| config.setDefaults(HoodieMetastoreConfig.class.getName()); | ||
| return config; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ | |
| package org.apache.hudi.common.table; | ||
|
|
||
| import org.apache.hudi.common.config.HoodieConfig; | ||
| import org.apache.hudi.common.config.HoodieMetastoreConfig; | ||
| import org.apache.hudi.common.config.SerializableConfiguration; | ||
| import org.apache.hudi.common.fs.ConsistencyGuardConfig; | ||
| import org.apache.hudi.common.fs.FSUtils; | ||
|
|
@@ -38,6 +39,7 @@ | |
| import org.apache.hudi.common.table.timeline.versioning.TimelineLayoutVersion; | ||
| import org.apache.hudi.common.util.CommitUtils; | ||
| import org.apache.hudi.common.util.Option; | ||
| import org.apache.hudi.common.util.ReflectionUtils; | ||
| import org.apache.hudi.common.util.StringUtils; | ||
| import org.apache.hudi.common.util.ValidationUtils; | ||
| import org.apache.hudi.exception.HoodieException; | ||
|
|
@@ -98,21 +100,22 @@ public class HoodieTableMetaClient implements Serializable { | |
| // NOTE: Since those two parameters lay on the hot-path of a lot of computations, we | ||
| // use tailored extension of the {@code Path} class allowing to avoid repetitive | ||
| // computations secured by its immutability | ||
| private SerializablePath basePath; | ||
| private SerializablePath metaPath; | ||
| protected SerializablePath basePath; | ||
| protected SerializablePath metaPath; | ||
|
|
||
| private transient HoodieWrapperFileSystem fs; | ||
| private boolean loadActiveTimelineOnLoad; | ||
| private SerializableConfiguration hadoopConf; | ||
| protected SerializableConfiguration hadoopConf; | ||
| private HoodieTableType tableType; | ||
| private TimelineLayoutVersion timelineLayoutVersion; | ||
| private HoodieTableConfig tableConfig; | ||
| private HoodieActiveTimeline activeTimeline; | ||
| protected HoodieTableConfig tableConfig; | ||
| protected HoodieActiveTimeline activeTimeline; | ||
| private HoodieArchivedTimeline archivedTimeline; | ||
| private ConsistencyGuardConfig consistencyGuardConfig = ConsistencyGuardConfig.newBuilder().build(); | ||
| private FileSystemRetryConfig fileSystemRetryConfig = FileSystemRetryConfig.newBuilder().build(); | ||
| protected HoodieMetastoreConfig metastoreConfig; | ||
|
|
||
| private HoodieTableMetaClient(Configuration conf, String basePath, boolean loadActiveTimelineOnLoad, | ||
| protected HoodieTableMetaClient(Configuration conf, String basePath, boolean loadActiveTimelineOnLoad, | ||
| ConsistencyGuardConfig consistencyGuardConfig, Option<TimelineLayoutVersion> layoutVersion, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why make these variables protected scope ? The class has no sub-classes ? |
||
| String payloadClassName, FileSystemRetryConfig fileSystemRetryConfig) { | ||
| LOG.info("Loading HoodieTableMetaClient from " + basePath); | ||
|
|
@@ -367,6 +370,13 @@ public synchronized HoodieArchivedTimeline getArchivedTimeline() { | |
| return archivedTimeline; | ||
| } | ||
|
|
||
| public HoodieMetastoreConfig getMetastoreConfig() { | ||
| if (metastoreConfig == null) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this method thread safe ? |
||
| metastoreConfig = new HoodieMetastoreConfig(); | ||
| } | ||
| return metastoreConfig; | ||
| } | ||
|
|
||
| /** | ||
| * Returns fresh new archived commits as a timeline from startTs (inclusive). | ||
| * | ||
|
|
@@ -451,7 +461,8 @@ public static HoodieTableMetaClient initTableAndGetMetaClient(Configuration hado | |
| HoodieTableConfig.create(fs, metaPathDir, props); | ||
| // We should not use fs.getConf as this might be different from the original configuration | ||
| // used to create the fs in unit tests | ||
| HoodieTableMetaClient metaClient = HoodieTableMetaClient.builder().setConf(hadoopConf).setBasePath(basePath).build(); | ||
| HoodieTableMetaClient metaClient = HoodieTableMetaClient.builder().setConf(hadoopConf).setBasePath(basePath) | ||
| .setProperties(props).build(); | ||
| LOG.info("Finished initializing Table of type " + metaClient.getTableConfig().getTableType() + " from " + basePath); | ||
| return metaClient; | ||
| } | ||
|
|
@@ -620,6 +631,21 @@ public void initializeBootstrapDirsIfNotExists() throws IOException { | |
| initializeBootstrapDirsIfNotExists(getHadoopConf(), basePath.toString(), getFs()); | ||
| } | ||
|
|
||
| private static HoodieTableMetaClient newMetaClient(Configuration conf, String basePath, boolean loadActiveTimelineOnLoad, | ||
| ConsistencyGuardConfig consistencyGuardConfig, Option<TimelineLayoutVersion> layoutVersion, | ||
| String payloadClassName, FileSystemRetryConfig fileSystemRetryConfig, Properties props) { | ||
| HoodieMetastoreConfig metastoreConfig = null == props | ||
| ? new HoodieMetastoreConfig.Builder().build() | ||
| : new HoodieMetastoreConfig.Builder().fromProperties(props).build(); | ||
| return metastoreConfig.enableMetastore() | ||
| ? (HoodieTableMetaClient) ReflectionUtils.loadClass("org.apache.hudi.common.table.HoodieTableMetastoreClient", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add some instructions to remove this reflection after the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HoodieTableMetastoreClient is under
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
after
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hudi-metastore depends on the hudi-common, reflection is necessary.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
well, ok |
||
| new Class<?>[]{Configuration.class, ConsistencyGuardConfig.class, FileSystemRetryConfig.class, String.class, String.class, HoodieMetastoreConfig.class}, | ||
| conf, consistencyGuardConfig, fileSystemRetryConfig, | ||
| props.getProperty(HoodieTableConfig.DATABASE_NAME.key()), props.getProperty(HoodieTableConfig.NAME.key()), metastoreConfig) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you check the NPE here ? |
||
| : new HoodieTableMetaClient(conf, basePath, | ||
| loadActiveTimelineOnLoad, consistencyGuardConfig, layoutVersion, payloadClassName, fileSystemRetryConfig); | ||
| } | ||
|
|
||
| public static Builder builder() { | ||
| return new Builder(); | ||
| } | ||
|
|
@@ -636,6 +662,7 @@ public static class Builder { | |
| private ConsistencyGuardConfig consistencyGuardConfig = ConsistencyGuardConfig.newBuilder().build(); | ||
| private FileSystemRetryConfig fileSystemRetryConfig = FileSystemRetryConfig.newBuilder().build(); | ||
| private Option<TimelineLayoutVersion> layoutVersion = Option.of(TimelineLayoutVersion.CURR_LAYOUT_VERSION); | ||
| private Properties props; | ||
|
|
||
| public Builder setConf(Configuration conf) { | ||
| this.conf = conf; | ||
|
|
@@ -672,11 +699,16 @@ public Builder setLayoutVersion(Option<TimelineLayoutVersion> layoutVersion) { | |
| return this; | ||
| } | ||
|
|
||
| public Builder setProperties(Properties properties) { | ||
| this.props = properties; | ||
| return this; | ||
| } | ||
|
|
||
| public HoodieTableMetaClient build() { | ||
| ValidationUtils.checkArgument(conf != null, "Configuration needs to be set to init HoodieTableMetaClient"); | ||
| ValidationUtils.checkArgument(basePath != null, "basePath needs to be set to init HoodieTableMetaClient"); | ||
| return new HoodieTableMetaClient(conf, basePath, | ||
| loadActiveTimelineOnLoad, consistencyGuardConfig, layoutVersion, payloadClassName, fileSystemRetryConfig); | ||
| return newMetaClient(conf, basePath, | ||
| loadActiveTimelineOnLoad, consistencyGuardConfig, layoutVersion, payloadClassName, fileSystemRetryConfig, props); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -245,7 +245,7 @@ public void deleteInstantFileIfExists(HoodieInstant instant) { | |
| } | ||
| } | ||
|
|
||
| private void deleteInstantFile(HoodieInstant instant) { | ||
| protected void deleteInstantFile(HoodieInstant instant) { | ||
| LOG.info("Deleting instant " + instant); | ||
| Path inFlightCommitFilePath = getInstantFileNamePath(instant.getFileName()); | ||
| try { | ||
|
|
@@ -536,7 +536,7 @@ private void transitionState(HoodieInstant fromInstant, HoodieInstant toInstant, | |
| transitionState(fromInstant, toInstant, data, false); | ||
| } | ||
|
|
||
| private void transitionState(HoodieInstant fromInstant, HoodieInstant toInstant, Option<byte[]> data, | ||
| protected void transitionState(HoodieInstant fromInstant, HoodieInstant toInstant, Option<byte[]> data, | ||
| boolean allowRedundantTransitions) { | ||
| ValidationUtils.checkArgument(fromInstant.getTimestamp().equals(toInstant.getTimestamp())); | ||
| try { | ||
|
|
@@ -566,7 +566,7 @@ private void transitionState(HoodieInstant fromInstant, HoodieInstant toInstant, | |
| } | ||
| } | ||
|
|
||
| private void revertCompleteToInflight(HoodieInstant completed, HoodieInstant inflight) { | ||
| protected void revertCompleteToInflight(HoodieInstant completed, HoodieInstant inflight) { | ||
| ValidationUtils.checkArgument(completed.getTimestamp().equals(inflight.getTimestamp())); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why make these methods protected ? |
||
| Path inFlightCommitFilePath = getInstantFileNamePath(inflight.getFileName()); | ||
| Path commitFilePath = getInstantFileNamePath(completed.getFileName()); | ||
|
|
@@ -632,7 +632,7 @@ public void saveToCompactionRequested(HoodieInstant instant, Option<byte[]> cont | |
| } | ||
|
|
||
| /** | ||
| * Saves content for inflight/requested REPLACE instant. | ||
| * Saves content for requested REPLACE instant. | ||
| */ | ||
| public void saveToPendingReplaceCommit(HoodieInstant instant, Option<byte[]> content) { | ||
| ValidationUtils.checkArgument(instant.getAction().equals(HoodieTimeline.REPLACE_COMMIT_ACTION)); | ||
|
|
@@ -719,7 +719,7 @@ public void saveToPendingIndexAction(HoodieInstant instant, Option<byte[]> conte | |
| createFileInMetaPath(instant.getFileName(), content, false); | ||
| } | ||
|
|
||
| private void createFileInMetaPath(String filename, Option<byte[]> content, boolean allowOverwrite) { | ||
| protected void createFileInMetaPath(String filename, Option<byte[]> content, boolean allowOverwrite) { | ||
| Path fullPath = getInstantFileNamePath(filename); | ||
| if (allowOverwrite || metaClient.getTimelineLayoutVersion().isNullVersion()) { | ||
| FileIOUtils.createFileInPath(metaClient.getFs(), fullPath, content); | ||
|
|
||
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.
Why is
isMetastoreEnabledturned on andStream.empty()is returned here?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.
For hudi metastore, timeline no more need to be archived
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.
For metastore implementation, is it possible to have something new like
MetastoreHoodieTiimelineArchiverimplement?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 is a good idea and I think it can be implemented in steps.