Skip to content

Commit 355adae

Browse files
authored
Make *StorageConfigurationInfo types immutable (#2236)
This change eventually enables usage of the `*StorageConfigurationInfo` in the `StorageCredentialCacheKey` due to the then memoized hash-code values, to eliminate a couple of JSON re-serializations.
1 parent 5fb38c5 commit 355adae

13 files changed

+395
-382
lines changed

polaris-core/src/main/java/org/apache/polaris/core/entity/CatalogEntity.java

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222

2323
import jakarta.annotation.Nonnull;
2424
import jakarta.annotation.Nullable;
25-
import java.util.ArrayList;
2625
import java.util.Collection;
2726
import java.util.HashMap;
2827
import java.util.HashSet;
@@ -269,37 +268,40 @@ public Builder setStorageConfigurationInfo(
269268
case S3:
270269
AwsStorageConfigInfo awsConfigModel = (AwsStorageConfigInfo) storageConfigModel;
271270
AwsStorageConfigurationInfo awsConfig =
272-
new AwsStorageConfigurationInfo(
273-
PolarisStorageConfigurationInfo.StorageType.S3,
274-
new ArrayList<>(allowedLocations),
275-
awsConfigModel.getRoleArn(),
276-
awsConfigModel.getExternalId(),
277-
awsConfigModel.getRegion(),
278-
awsConfigModel.getEndpoint(),
279-
awsConfigModel.getStsEndpoint(),
280-
awsConfigModel.getPathStyleAccess(),
281-
awsConfigModel.getEndpointInternal());
271+
AwsStorageConfigurationInfo.builder()
272+
.allowedLocations(allowedLocations)
273+
.roleARN(awsConfigModel.getRoleArn())
274+
.externalId(awsConfigModel.getExternalId())
275+
.region(awsConfigModel.getRegion())
276+
.endpoint(awsConfigModel.getEndpoint())
277+
.stsEndpoint(awsConfigModel.getStsEndpoint())
278+
.pathStyleAccess(awsConfigModel.getPathStyleAccess())
279+
.endpointInternal(awsConfigModel.getEndpointInternal())
280+
.build();
282281
awsConfig.validateArn(awsConfigModel.getRoleArn());
283282
config = awsConfig;
284283
break;
285284
case AZURE:
286285
AzureStorageConfigInfo azureConfigModel = (AzureStorageConfigInfo) storageConfigModel;
287-
AzureStorageConfigurationInfo azureConfigInfo =
288-
new AzureStorageConfigurationInfo(
289-
new ArrayList<>(allowedLocations), azureConfigModel.getTenantId());
290-
azureConfigInfo.setMultiTenantAppName(azureConfigModel.getMultiTenantAppName());
291-
azureConfigInfo.setConsentUrl(azureConfigModel.getConsentUrl());
292-
config = azureConfigInfo;
286+
config =
287+
AzureStorageConfigurationInfo.builder()
288+
.allowedLocations(allowedLocations)
289+
.tenantId(azureConfigModel.getTenantId())
290+
.multiTenantAppName(azureConfigModel.getMultiTenantAppName())
291+
.consentUrl(azureConfigModel.getConsentUrl())
292+
.build();
293293
break;
294294
case GCS:
295-
GcpStorageConfigurationInfo gcpConfig =
296-
new GcpStorageConfigurationInfo(new ArrayList<>(allowedLocations));
297-
gcpConfig.setGcpServiceAccount(
298-
((GcpStorageConfigInfo) storageConfigModel).getGcsServiceAccount());
299-
config = gcpConfig;
295+
config =
296+
GcpStorageConfigurationInfo.builder()
297+
.allowedLocations(allowedLocations)
298+
.gcpServiceAccount(
299+
((GcpStorageConfigInfo) storageConfigModel).getGcsServiceAccount())
300+
.build();
300301
break;
301302
case FILE:
302-
config = new FileStorageConfigurationInfo(new ArrayList<>(allowedLocations));
303+
config =
304+
FileStorageConfigurationInfo.builder().allowedLocations(allowedLocations).build();
303305
break;
304306
default:
305307
throw new IllegalStateException(

polaris-core/src/main/java/org/apache/polaris/core/storage/FileStorageConfigurationInfo.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,37 @@
1818
*/
1919
package org.apache.polaris.core.storage;
2020

21-
import com.fasterxml.jackson.annotation.JsonProperty;
22-
import jakarta.annotation.Nonnull;
23-
import java.util.List;
21+
import com.fasterxml.jackson.annotation.JsonTypeName;
22+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
23+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
2424
import java.util.Locale;
25+
import org.apache.polaris.immutables.PolarisImmutable;
2526

2627
/**
2728
* Support for file:// URLs in storage configuration. This is pretty-much only used for testing.
2829
* Supports URLs that start with file:// or /, but also supports wildcard (*) to support certain
2930
* test cases.
3031
*/
31-
public class FileStorageConfigurationInfo extends PolarisStorageConfigurationInfo {
32+
@PolarisImmutable
33+
@JsonSerialize(as = ImmutableFileStorageConfigurationInfo.class)
34+
@JsonDeserialize(as = ImmutableFileStorageConfigurationInfo.class)
35+
@JsonTypeName("FileStorageConfigurationInfo")
36+
public abstract class FileStorageConfigurationInfo extends PolarisStorageConfigurationInfo {
3237

33-
public FileStorageConfigurationInfo(
34-
@JsonProperty(value = "allowedLocations", required = true) @Nonnull
35-
List<String> allowedLocations) {
36-
super(StorageType.FILE, allowedLocations);
38+
public static ImmutableFileStorageConfigurationInfo.Builder builder() {
39+
return ImmutableFileStorageConfigurationInfo.builder();
3740
}
3841

3942
@Override
4043
public String getFileIoImplClassName() {
4144
return "org.apache.iceberg.hadoop.HadoopFileIO";
4245
}
4346

47+
@Override
48+
public StorageType getStorageType() {
49+
return StorageType.FILE;
50+
}
51+
4452
@Override
4553
public void validatePrefixForStorageType(String loc) {
4654
if (getStorageType().getPrefixes().stream()

polaris-core/src/main/java/org/apache/polaris/core/storage/PolarisStorageConfigurationInfo.java

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
*/
1919
package org.apache.polaris.core.storage;
2020

21+
import com.fasterxml.jackson.annotation.JsonIgnore;
22+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
2123
import com.fasterxml.jackson.annotation.JsonInclude;
22-
import com.fasterxml.jackson.annotation.JsonProperty;
2324
import com.fasterxml.jackson.annotation.JsonSubTypes;
2425
import com.fasterxml.jackson.annotation.JsonTypeInfo;
2526
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -46,6 +47,7 @@
4647
import org.apache.polaris.core.storage.aws.AwsStorageConfigurationInfo;
4748
import org.apache.polaris.core.storage.azure.AzureStorageConfigurationInfo;
4849
import org.apache.polaris.core.storage.gcp.GcpStorageConfigurationInfo;
50+
import org.immutables.value.Value;
4951
import org.slf4j.Logger;
5052
import org.slf4j.LoggerFactory;
5153

@@ -65,40 +67,28 @@
6567
@JsonSubTypes.Type(value = GcpStorageConfigurationInfo.class),
6668
@JsonSubTypes.Type(value = FileStorageConfigurationInfo.class),
6769
})
70+
@JsonIgnoreProperties(ignoreUnknown = true)
6871
public abstract class PolarisStorageConfigurationInfo {
6972

7073
private static final Logger LOGGER =
7174
LoggerFactory.getLogger(PolarisStorageConfigurationInfo.class);
7275

73-
// a list of allowed locations
74-
private final List<String> allowedLocations;
75-
76-
// storage type
77-
private final StorageType storageType;
78-
79-
public PolarisStorageConfigurationInfo(
80-
@JsonProperty(value = "storageType", required = true) @Nonnull StorageType storageType,
81-
@JsonProperty(value = "allowedLocations", required = true) @Nonnull
82-
List<String> allowedLocations) {
83-
this(storageType, allowedLocations, true);
84-
}
85-
86-
protected PolarisStorageConfigurationInfo(
87-
StorageType storageType, List<String> allowedLocations, boolean validatePrefix) {
88-
this.allowedLocations = allowedLocations;
89-
this.storageType = storageType;
90-
if (validatePrefix) {
91-
allowedLocations.forEach(this::validatePrefixForStorageType);
76+
@Value.Check
77+
protected void check() {
78+
if (validatePrefix()) {
79+
getAllowedLocations().forEach(this::validatePrefixForStorageType);
9280
}
9381
}
9482

95-
public List<String> getAllowedLocations() {
96-
return allowedLocations;
83+
@JsonIgnore
84+
@Value.Auxiliary
85+
public boolean validatePrefix() {
86+
return true;
9787
}
9888

99-
public StorageType getStorageType() {
100-
return storageType;
101-
}
89+
public abstract List<String> getAllowedLocations();
90+
91+
public abstract StorageType getStorageType();
10292

10393
private static final ObjectMapper DEFAULT_MAPPER;
10494

@@ -213,11 +203,12 @@ private static List<String> userSpecifiedWriteLocations(Map<String, String> prop
213203

214204
/** Validate if the provided allowed locations are valid for the storage type */
215205
protected void validatePrefixForStorageType(String loc) {
216-
if (storageType.prefixes.stream().noneMatch(p -> loc.toLowerCase(Locale.ROOT).startsWith(p))) {
206+
if (getStorageType().prefixes.stream()
207+
.noneMatch(p -> loc.toLowerCase(Locale.ROOT).startsWith(p))) {
217208
throw new IllegalArgumentException(
218209
String.format(
219210
"Location prefix not allowed: '%s', expected prefixes: '%s'",
220-
loc, String.join(",", storageType.prefixes)));
211+
loc, String.join(",", getStorageType().prefixes)));
221212
}
222213
}
223214

polaris-core/src/main/java/org/apache/polaris/core/storage/StorageConfigurationOverride.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,36 @@
3030
public class StorageConfigurationOverride extends PolarisStorageConfigurationInfo {
3131

3232
private final PolarisStorageConfigurationInfo parentStorageConfiguration;
33+
private final List<String> allowedLocations;
3334

3435
public StorageConfigurationOverride(
3536
@Nonnull PolarisStorageConfigurationInfo parentStorageConfiguration,
3637
List<String> allowedLocations) {
37-
super(parentStorageConfiguration.getStorageType(), allowedLocations, false);
3838
this.parentStorageConfiguration = parentStorageConfiguration;
39+
this.allowedLocations = List.copyOf(allowedLocations);
3940
allowedLocations.forEach(this::validatePrefixForStorageType);
4041
}
4142

43+
@Override
44+
public List<String> getAllowedLocations() {
45+
return allowedLocations;
46+
}
47+
48+
@Override
49+
public StorageType getStorageType() {
50+
return parentStorageConfiguration.getStorageType();
51+
}
52+
4253
@Override
4354
public String getFileIoImplClassName() {
4455
return parentStorageConfiguration.getFileIoImplClassName();
4556
}
4657

58+
@Override
59+
public boolean validatePrefix() {
60+
return false;
61+
}
62+
4763
// delegate to the wrapped class in case they override the parent behavior
4864
@Override
4965
protected void validatePrefixForStorageType(String loc) {

0 commit comments

Comments
 (0)