-
Notifications
You must be signed in to change notification settings - Fork 3k
Core: Send Idempotency-Key on mutation requests when advertised #14740
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -160,6 +160,7 @@ public class RESTSessionCatalog extends BaseViewSessionCatalog | |
| private Integer pageSize = null; | ||
| private CloseableGroup closeables = null; | ||
| private Set<Endpoint> endpoints; | ||
| private Supplier<Map<String, String>> mutationHeaders = Map::of; | ||
|
|
||
| public RESTSessionCatalog() { | ||
| this( | ||
|
|
@@ -203,6 +204,11 @@ public void initialize(String name, Map<String, String> unresolved) { | |
| // build the final configuration and set up the catalog's auth | ||
| Map<String, String> mergedProps = config.merge(props); | ||
|
|
||
| // Enable Idempotency-Key header for mutation endpoints if the server advertises support | ||
| if (config.idempotencyKeyLifetime() != null) { | ||
| this.mutationHeaders = RESTUtil::idempotencyHeaders; | ||
| } | ||
|
|
||
| if (config.endpoints().isEmpty()) { | ||
| this.endpoints = | ||
| PropertyUtil.propertyAsBoolean( | ||
|
|
@@ -307,7 +313,8 @@ public boolean dropTable(SessionContext context, TableIdentifier identifier) { | |
| AuthSession contextualSession = authManager.contextualSession(context, catalogAuth); | ||
| client | ||
| .withAuthSession(contextualSession) | ||
| .delete(paths.table(identifier), null, Map.of(), ErrorHandlers.tableErrorHandler()); | ||
| .delete( | ||
| paths.table(identifier), null, mutationHeaders, ErrorHandlers.tableErrorHandler()); | ||
| return true; | ||
| } catch (NoSuchTableException e) { | ||
| return false; | ||
|
|
@@ -327,7 +334,7 @@ public boolean purgeTable(SessionContext context, TableIdentifier identifier) { | |
| paths.table(identifier), | ||
| ImmutableMap.of("purgeRequested", "true"), | ||
| null, | ||
| Map.of(), | ||
| mutationHeaders, | ||
| ErrorHandlers.tableErrorHandler()); | ||
| return true; | ||
| } catch (NoSuchTableException e) { | ||
|
|
@@ -348,7 +355,7 @@ public void renameTable(SessionContext context, TableIdentifier from, TableIdent | |
| AuthSession contextualSession = authManager.contextualSession(context, catalogAuth); | ||
| client | ||
| .withAuthSession(contextualSession) | ||
| .post(paths.rename(), request, null, Map.of(), ErrorHandlers.tableErrorHandler()); | ||
| .post(paths.rename(), request, null, mutationHeaders, ErrorHandlers.tableErrorHandler()); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -455,6 +462,7 @@ public Table loadTable(SessionContext context, TableIdentifier identifier) { | |
| tableClient, | ||
| paths.table(finalIdentifier), | ||
| Map::of, | ||
| mutationHeaders, | ||
| tableFileIO(context, tableConf, response.credentials()), | ||
| tableMetadata, | ||
| endpoints); | ||
|
|
@@ -523,7 +531,7 @@ public Table registerTable( | |
| paths.register(ident.namespace()), | ||
| request, | ||
| LoadTableResponse.class, | ||
| Map.of(), | ||
| mutationHeaders, | ||
| ErrorHandlers.tableErrorHandler()); | ||
|
|
||
| Map<String, String> tableConf = response.config(); | ||
|
|
@@ -534,6 +542,7 @@ public Table registerTable( | |
| tableClient, | ||
| paths.table(ident), | ||
| Map::of, | ||
| mutationHeaders, | ||
| tableFileIO(context, tableConf, response.credentials()), | ||
| response.tableMetadata(), | ||
| endpoints); | ||
|
|
@@ -559,7 +568,7 @@ public void createNamespace( | |
| paths.namespaces(), | ||
| request, | ||
| CreateNamespaceResponse.class, | ||
| Map.of(), | ||
| mutationHeaders, | ||
| ErrorHandlers.namespaceErrorHandler()); | ||
| } | ||
|
|
||
|
|
@@ -645,7 +654,11 @@ public boolean dropNamespace(SessionContext context, Namespace ns) { | |
| AuthSession contextualSession = authManager.contextualSession(context, catalogAuth); | ||
| client | ||
| .withAuthSession(contextualSession) | ||
| .delete(paths.namespace(ns), null, Map.of(), ErrorHandlers.dropNamespaceErrorHandler()); | ||
| .delete( | ||
| paths.namespace(ns), | ||
| null, | ||
| mutationHeaders, | ||
| ErrorHandlers.dropNamespaceErrorHandler()); | ||
| return true; | ||
| } catch (NoSuchNamespaceException e) { | ||
| return false; | ||
|
|
@@ -669,7 +682,7 @@ public boolean updateNamespaceMetadata( | |
| paths.namespaceProperties(ns), | ||
| request, | ||
| UpdateNamespacePropertiesResponse.class, | ||
| Map.of(), | ||
| mutationHeaders, | ||
| ErrorHandlers.namespaceErrorHandler()); | ||
|
|
||
| return !response.updated().isEmpty(); | ||
|
|
@@ -782,7 +795,7 @@ public Table create() { | |
| paths.tables(ident.namespace()), | ||
| request, | ||
| LoadTableResponse.class, | ||
| Map.of(), | ||
| mutationHeaders, | ||
| ErrorHandlers.tableErrorHandler()); | ||
|
|
||
| Map<String, String> tableConf = response.config(); | ||
|
|
@@ -793,6 +806,7 @@ public Table create() { | |
| tableClient, | ||
| paths.table(ident), | ||
| Map::of, | ||
| mutationHeaders, | ||
| tableFileIO(context, tableConf, response.credentials()), | ||
| response.tableMetadata(), | ||
| endpoints); | ||
|
|
@@ -820,6 +834,7 @@ public Transaction createTransaction() { | |
| tableClient, | ||
| paths.table(ident), | ||
| Map::of, | ||
| mutationHeaders, | ||
|
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. are we missing the same change for L806?
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. Fixed L806 to use |
||
| tableFileIO(context, tableConf, response.credentials()), | ||
| RESTTableOperations.UpdateType.CREATE, | ||
| createChanges(meta), | ||
|
|
@@ -883,6 +898,7 @@ public Transaction replaceTransaction() { | |
| tableClient, | ||
| paths.table(ident), | ||
| Map::of, | ||
| mutationHeaders, | ||
| tableFileIO(context, tableConf, response.credentials()), | ||
| RESTTableOperations.UpdateType.REPLACE, | ||
| changes.build(), | ||
|
|
@@ -932,7 +948,7 @@ private LoadTableResponse stageCreate() { | |
| paths.tables(ident.namespace()), | ||
| request, | ||
| LoadTableResponse.class, | ||
| Map.of(), | ||
| mutationHeaders, | ||
| ErrorHandlers.tableErrorHandler()); | ||
| } | ||
| } | ||
|
|
@@ -1019,7 +1035,10 @@ private FileIO tableFileIO( | |
| * | ||
| * @param restClient the REST client to use for communicating with the catalog server | ||
| * @param path the REST path for the table | ||
| * @param headers a supplier for additional HTTP headers to include in requests | ||
| * @param readHeaders a supplier for additional HTTP headers to include in read requests | ||
| * (GET/HEAD) | ||
| * @param mutationHeaderSupplier a supplier for additional HTTP headers to include in mutation | ||
| * requests (POST/DELETE) | ||
| * @param fileIO the FileIO implementation for reading and writing table metadata and data files | ||
| * @param current the current table metadata | ||
| * @param supportedEndpoints the set of supported REST endpoints | ||
|
|
@@ -1028,11 +1047,13 @@ private FileIO tableFileIO( | |
| protected RESTTableOperations newTableOps( | ||
| RESTClient restClient, | ||
| String path, | ||
| Supplier<Map<String, String>> headers, | ||
| Supplier<Map<String, String>> readHeaders, | ||
| Supplier<Map<String, String>> mutationHeaderSupplier, | ||
| FileIO fileIO, | ||
| TableMetadata current, | ||
| Set<Endpoint> supportedEndpoints) { | ||
| return new RESTTableOperations(restClient, path, headers, fileIO, current, supportedEndpoints); | ||
| return new RESTTableOperations( | ||
| restClient, path, readHeaders, mutationHeaderSupplier, fileIO, current, supportedEndpoints); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -1044,7 +1065,10 @@ protected RESTTableOperations newTableOps( | |
| * | ||
| * @param restClient the REST client to use for communicating with the catalog server | ||
| * @param path the REST path for the table | ||
| * @param headers a supplier for additional HTTP headers to include in requests | ||
| * @param readHeaders a supplier for additional HTTP headers to include in read requests | ||
| * (GET/HEAD) | ||
| * @param mutationHeaderSupplier a supplier for additional HTTP headers to include in mutation | ||
| * requests (POST/DELETE) | ||
| * @param fileIO the FileIO implementation for reading and writing table metadata and data files | ||
| * @param updateType the {@link RESTTableOperations.UpdateType} being performed | ||
| * @param createChanges the list of metadata updates to apply during table creation or replacement | ||
|
|
@@ -1055,14 +1079,23 @@ protected RESTTableOperations newTableOps( | |
| protected RESTTableOperations newTableOps( | ||
| RESTClient restClient, | ||
| String path, | ||
| Supplier<Map<String, String>> headers, | ||
| Supplier<Map<String, String>> readHeaders, | ||
| Supplier<Map<String, String>> mutationHeaderSupplier, | ||
| FileIO fileIO, | ||
| RESTTableOperations.UpdateType updateType, | ||
| List<MetadataUpdate> createChanges, | ||
| TableMetadata current, | ||
| Set<Endpoint> supportedEndpoints) { | ||
| return new RESTTableOperations( | ||
| restClient, path, headers, fileIO, updateType, createChanges, current, supportedEndpoints); | ||
| restClient, | ||
| path, | ||
| readHeaders, | ||
| mutationHeaderSupplier, | ||
| fileIO, | ||
| updateType, | ||
| createChanges, | ||
| current, | ||
| supportedEndpoints); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -1073,18 +1106,23 @@ protected RESTTableOperations newTableOps( | |
| * | ||
| * @param restClient the REST client to use for communicating with the catalog server | ||
| * @param path the REST path for the view | ||
| * @param headers a supplier for additional HTTP headers to include in requests | ||
| * @param readHeaders a supplier for additional HTTP headers to include in read requests | ||
| * (GET/HEAD) | ||
| * @param mutationHeaderSupplier a supplier for additional HTTP headers to include in mutation | ||
| * requests (POST/DELETE) | ||
| * @param current the current view metadata | ||
| * @param supportedEndpoints the set of supported REST endpoints | ||
| * @return a new RESTViewOperations instance | ||
| */ | ||
| protected RESTViewOperations newViewOps( | ||
| RESTClient restClient, | ||
| String path, | ||
| Supplier<Map<String, String>> headers, | ||
| Supplier<Map<String, String>> readHeaders, | ||
| Supplier<Map<String, String>> mutationHeaderSupplier, | ||
| ViewMetadata current, | ||
| Set<Endpoint> supportedEndpoints) { | ||
| return new RESTViewOperations(restClient, path, headers, current, supportedEndpoints); | ||
| return new RESTViewOperations( | ||
| restClient, path, readHeaders, mutationHeaderSupplier, current, supportedEndpoints); | ||
| } | ||
|
|
||
| private static ConfigResponse fetchConfig( | ||
|
|
@@ -1148,7 +1186,7 @@ public void commitTransaction(SessionContext context, List<TableCommit> commits) | |
| paths.commitTransaction(), | ||
| new CommitTransactionRequest(tableChanges), | ||
| null, | ||
| Map.of(), | ||
| mutationHeaders, | ||
| ErrorHandlers.tableCommitHandler()); | ||
| } | ||
|
|
||
|
|
@@ -1235,6 +1273,7 @@ public View loadView(SessionContext context, TableIdentifier identifier) { | |
| client.withAuthSession(tableSession), | ||
| paths.view(identifier), | ||
| Map::of, | ||
| mutationHeaders, | ||
| metadata, | ||
| endpoints); | ||
|
|
||
|
|
@@ -1255,7 +1294,7 @@ public boolean dropView(SessionContext context, TableIdentifier identifier) { | |
| AuthSession contextualSession = authManager.contextualSession(context, catalogAuth); | ||
| client | ||
| .withAuthSession(contextualSession) | ||
| .delete(paths.view(identifier), null, Map.of(), ErrorHandlers.viewErrorHandler()); | ||
| .delete(paths.view(identifier), null, mutationHeaders, ErrorHandlers.viewErrorHandler()); | ||
| return true; | ||
| } catch (NoSuchViewException e) { | ||
| return false; | ||
|
|
@@ -1274,7 +1313,7 @@ public void renameView(SessionContext context, TableIdentifier from, TableIdenti | |
| AuthSession contextualSession = authManager.contextualSession(context, catalogAuth); | ||
| client | ||
| .withAuthSession(contextualSession) | ||
| .post(paths.renameView(), request, null, Map.of(), ErrorHandlers.viewErrorHandler()); | ||
| .post(paths.renameView(), request, null, mutationHeaders, ErrorHandlers.viewErrorHandler()); | ||
| } | ||
|
|
||
| private class RESTViewBuilder implements ViewBuilder { | ||
|
|
@@ -1404,7 +1443,7 @@ public View create() { | |
| paths.views(identifier.namespace()), | ||
| request, | ||
| LoadViewResponse.class, | ||
| Map.of(), | ||
| mutationHeaders, | ||
| ErrorHandlers.viewErrorHandler()); | ||
|
|
||
| Map<String, String> tableConf = response.config(); | ||
|
|
@@ -1414,6 +1453,7 @@ public View create() { | |
| client.withAuthSession(tableSession), | ||
| paths.view(identifier), | ||
| Map::of, | ||
| mutationHeaders, | ||
| response.metadata(), | ||
| endpoints); | ||
|
|
||
|
|
@@ -1505,6 +1545,7 @@ private View replace(LoadViewResponse response) { | |
| client.withAuthSession(tableSession), | ||
| paths.view(identifier), | ||
| Map::of, | ||
| mutationHeaders, | ||
| metadata, | ||
| endpoints); | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
not adjusting
new RESTMetricsReporter(restClient, metricsEndpoint, Map::of);is probably fine for now as well, since we didn't add the param to the Spec and because typically we don't care too much whether metrics actually arrive or not, since it's best-effort and we don't want to interfere with the read/write path and add additional latency