Skip to content

Commit 75a5952

Browse files
committed
[WIP] Support multiple DS
1 parent 66e9535 commit 75a5952

File tree

15 files changed

+236
-103
lines changed

15 files changed

+236
-103
lines changed

extension/persistence/relational-jdbc/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ dependencies {
3232
compileOnly(libs.jakarta.inject.api)
3333

3434
implementation(libs.smallrye.common.annotation) // @Identifier
35+
compileOnly(libs.smallrye.config.core)
3536

3637
testImplementation(libs.mockito.junit.jupiter)
3738

extension/persistence/relational-jdbc/src/main/java/org/apache/polaris/extension/persistence/relational/jdbc/DatasourceOperations.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838

3939
public class DatasourceOperations {
4040

41-
private static final String CONSTRAINT_VIOLATION_SQL_CODE = "23505";
41+
private static final String CONSTRAINT_VIOLATION_SQL_CODE_POSTGRES = "23505";
42+
private static final String TABLE_DOES_NOT_EXIST_SQL_CODE_POSTGRES = "42P01";
4243

4344
private final DataSource datasource;
4445

@@ -182,7 +183,11 @@ public interface TransactionCallback {
182183
}
183184

184185
public boolean isConstraintViolation(SQLException e) {
185-
return CONSTRAINT_VIOLATION_SQL_CODE.equals(e.getSQLState());
186+
return CONSTRAINT_VIOLATION_SQL_CODE_POSTGRES.equals(e.getSQLState());
187+
}
188+
189+
public boolean isTableNotExists(SQLException e) {
190+
return TABLE_DOES_NOT_EXIST_SQL_CODE_POSTGRES.equals(e.getSQLState());
186191
}
187192

188193
private Connection borrowConnection() throws SQLException {
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616
* specific language governing permissions and limitations
1717
* under the License.
1818
*/
19-
2019
package org.apache.polaris.extension.persistence.relational.jdbc;
2120

2221
import javax.sql.DataSource;
2322

24-
public interface JdbcDatasource {
25-
DataSource fromRealmId(String realmId);
23+
public interface DatasourceSupplier {
24+
DataSource fromRealmId(String realmId);
2625
}

extension/persistence/relational-jdbc/src/main/java/org/apache/polaris/extension/persistence/relational/jdbc/JdbcBasePersistenceImpl.java

+6
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,12 @@ private PolarisBaseEntity getPolarisBaseEntity(String query) {
315315
return results.getFirst();
316316
}
317317
} catch (SQLException e) {
318+
// This look-up is used for checking if the realm is bootstrap or not.
319+
// If we have 1 DB per realm it might happen that the realm is not boostrap
320+
// at all.
321+
if (datasourceOperations.isTableNotExists(e)) {
322+
return null;
323+
}
318324
throw new RuntimeException(
319325
String.format("Failed to retrieve polaris entity due to %s", e.getMessage()), e);
320326
}

extension/persistence/relational-jdbc/src/main/java/org/apache/polaris/extension/persistence/relational/jdbc/JdbcMetaStoreManagerFactory.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import io.smallrye.common.annotation.Identifier;
2222
import jakarta.annotation.Nullable;
2323
import jakarta.enterprise.context.ApplicationScoped;
24-
import jakarta.enterprise.inject.Instance;
2524
import jakarta.inject.Inject;
2625
import java.sql.Connection;
2726
import java.sql.SQLException;
@@ -73,7 +72,7 @@ public class JdbcMetaStoreManagerFactory implements MetaStoreManagerFactory {
7372
protected final PolarisDiagnostics diagServices = new PolarisDefaultDiagServiceImpl();
7473

7574
@Inject PolarisStorageIntegrationProvider storageIntegrationProvider;
76-
@Inject JdbcDatasource jdbcDatasource;
75+
@Inject DatasourceSupplier jdbcDatasource;
7776

7877
protected JdbcMetaStoreManagerFactory() {}
7978

@@ -93,7 +92,8 @@ protected PolarisMetaStoreManager createNewMetaStoreManager() {
9392

9493
private void initializeForRealm(
9594
RealmContext realmContext, RootCredentialsSet rootCredentialsSet, boolean isBootstrap) {
96-
DatasourceOperations databaseOperations = getDatasourceOperations(isBootstrap, realmContext.getRealmIdentifier());
95+
DatasourceOperations databaseOperations =
96+
getDatasourceOperations(isBootstrap, realmContext.getRealmIdentifier());
9797
sessionSupplierMap.put(
9898
realmContext.getRealmIdentifier(),
9999
() ->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.polaris.extension.persistence.relational.jdbc;
20+
21+
import io.smallrye.config.ConfigMapping;
22+
import java.util.Map;
23+
24+
@ConfigMapping(prefix = "polaris.relation.jdbc")
25+
public interface RelationalJdbcConfiguration {
26+
Map<String, String> datasource();
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.polaris.admintool.config;
20+
21+
import io.quarkus.arc.InstanceHandle;
22+
import java.util.List;
23+
import javax.sql.DataSource;
24+
import org.apache.polaris.extension.persistence.relational.jdbc.DatasourceSupplier;
25+
import org.apache.polaris.extension.persistence.relational.jdbc.RelationalJdbcConfiguration;
26+
27+
public class QuarkusDatasourceSupplier implements DatasourceSupplier {
28+
private final List<InstanceHandle<DataSource>> dataSources;
29+
private final RelationalJdbcConfiguration relationalJdbcConfiguration;
30+
31+
public static final String DEFAULT_DATA_SOURCE_NAME = "<default>";
32+
33+
public QuarkusDatasourceSupplier(
34+
RelationalJdbcConfiguration relationalJdbcConfiguration,
35+
List<InstanceHandle<DataSource>> dataSources) {
36+
this.relationalJdbcConfiguration = relationalJdbcConfiguration;
37+
this.dataSources = dataSources;
38+
}
39+
40+
@Override
41+
public DataSource fromRealmId(String realmId) {
42+
String dataSourceName =
43+
relationalJdbcConfiguration.datasource().getOrDefault(realmId, DEFAULT_DATA_SOURCE_NAME);
44+
for (InstanceHandle<DataSource> handle : dataSources) {
45+
String name = handle.getBean().getName();
46+
name = name == null ? DEFAULT_DATA_SOURCE_NAME : name;
47+
// if realm isolation is DB then there should be only one DS configured.
48+
if (name.equals(dataSourceName)) {
49+
return handle.get();
50+
}
51+
}
52+
throw new IllegalStateException("No datasource configured with name: " + realmId);
53+
}
54+
}

quarkus/admin/src/main/java/org/apache/polaris/admintool/config/QuarkusJdbcDataSource.java

-56
This file was deleted.

quarkus/admin/src/main/java/org/apache/polaris/admintool/config/QuarkusProducers.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,18 @@
2828
import jakarta.enterprise.inject.Produces;
2929
import java.time.Clock;
3030
import java.util.List;
31-
31+
import javax.sql.DataSource;
3232
import org.apache.polaris.core.PolarisDefaultDiagServiceImpl;
3333
import org.apache.polaris.core.PolarisDiagnostics;
3434
import org.apache.polaris.core.config.PolarisConfigurationStore;
3535
import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
3636
import org.apache.polaris.core.storage.PolarisStorageConfigurationInfo;
3737
import org.apache.polaris.core.storage.PolarisStorageIntegration;
3838
import org.apache.polaris.core.storage.PolarisStorageIntegrationProvider;
39-
import org.apache.polaris.extension.persistence.relational.jdbc.JdbcDatasource;
39+
import org.apache.polaris.extension.persistence.relational.jdbc.DatasourceSupplier;
40+
import org.apache.polaris.extension.persistence.relational.jdbc.RelationalJdbcConfiguration;
4041
import org.eclipse.microprofile.config.inject.ConfigProperty;
4142

42-
import javax.sql.DataSource;
43-
4443
public class QuarkusProducers {
4544

4645
@Produces
@@ -85,7 +84,9 @@ public PolarisConfigurationStore configurationStore() {
8584
}
8685

8786
@Produces
88-
public JdbcDatasource jdbcDatasource(@All List<InstanceHandle<DataSource>> dataSources) {
89-
return new QuarkusJdbcDataSource(dataSources);
87+
public DatasourceSupplier jdbcDatasource(
88+
RelationalJdbcConfiguration relationalJdbcConfiguration,
89+
@All List<InstanceHandle<DataSource>> dataSources) {
90+
return new QuarkusDatasourceSupplier(relationalJdbcConfiguration, dataSources);
9091
}
9192
}

quarkus/admin/src/main/resources/application.properties

+16-12
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,20 @@ quarkus.index-dependency.guava.artifact-id=guava
5050
quarkus.index-dependency.protobuf.group-id=com.google.protobuf
5151
quarkus.index-dependency.protobuf.artifact-id=protobuf-java
5252

53-
quarkus.datasource.\"realm1\".db-kind=pgsql
54-
quarkus.datasource.\"realm1\".jdbc.url=polaris
55-
quarkus.datasource.\"realm1\".username=polaris
56-
quarkus.datasource.\"realm1\".password=polaris
57-
quarkus.datasource.\"realm2\".db-kind=pgsql
58-
quarkus.datasource.\"realm2\".jdbc.url=polaris
59-
quarkus.datasource.\"realm2\".username=polaris
60-
quarkus.datasource.\"realm2\".password=polaris
61-
quarkus.datasource.\"realm3\".db-kind=pgsql
62-
quarkus.datasource.\"realm3\".jdbc.url=polaris
63-
quarkus.datasource.\"realm3\".username=polaris
64-
quarkus.datasource.\"realm3\".password=polaris
53+
#quarkus.datasource.db-kind=pgsql
54+
#quarkus.datasource.jdbc.url=polaris
55+
#quarkus.datasource.username=polaris
56+
#quarkus.datasource.password=polaris
57+
quarkus.datasource.\"realm1_ds\".db-kind=pgsql
58+
quarkus.datasource.\"realm1_ds\".jdbc.url=polaris
59+
quarkus.datasource.\"realm1_ds\".username=polaris
60+
quarkus.datasource.\"realm1_ds\".password=polaris
61+
quarkus.datasource.\"realm2_ds\".db-kind=pgsql
62+
quarkus.datasource.\"realm2_ds\".jdbc.url=polaris
63+
quarkus.datasource.\"realm2_ds\".username=polaris
64+
quarkus.datasource.\"realm2_ds\".password=polaris
65+
quarkus.datasource.\"realm3_ds\".db-kind=pgsql
66+
quarkus.datasource.\"realm3_ds\".jdbc.url=polaris
67+
quarkus.datasource.\"realm3_ds\".username=polaris
68+
quarkus.datasource.\"realm3_ds\".password=polaris
6569

quarkus/admin/src/test/java/org/apache/polaris/admintool/relational/jdbc/RelationalJdbcAdminProfile.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ public List<TestResourceEntry> testResources() {
3636
return List.of(
3737
new TestResourceEntry(
3838
PostgresRelationalJdbcLifeCycleManagement.class,
39-
Map.of(INIT_SCRIPT, "org/apache/polaris/admintool/jdbc/init.sql")));
39+
Map.of(
40+
INIT_SCRIPT,
41+
"org/apache/polaris/admintool/jdbc/init.sql",
42+
"databases",
43+
"realm1,realm2,realm3")));
4044
}
4145
}

quarkus/service/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ dependencies {
108108
testImplementation("software.amazon.awssdk:kms")
109109
testImplementation("software.amazon.awssdk:dynamodb")
110110

111-
runtimeOnly(project(":polaris-relational-jdbc"))
111+
implementation(project(":polaris-relational-jdbc"))
112112
runtimeOnly("io.quarkus:quarkus-jdbc-postgresql") {
113113
exclude(group = "org.antlr", module = "antlr4-runtime")
114114
exclude(group = "org.scala-lang", module = "scala-library")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.polaris.service.quarkus.config;
20+
21+
import io.quarkus.arc.InstanceHandle;
22+
import java.util.List;
23+
import javax.sql.DataSource;
24+
import org.apache.polaris.extension.persistence.relational.jdbc.DatasourceSupplier;
25+
import org.apache.polaris.extension.persistence.relational.jdbc.RelationalJdbcConfiguration;
26+
27+
public class QuarkusDatasourceSupplier implements DatasourceSupplier {
28+
private final List<InstanceHandle<DataSource>> dataSources;
29+
private final RelationalJdbcConfiguration relationalJdbcConfiguration;
30+
31+
public static final String DEFAULT_DATA_SOURCE_NAME = "<default>";
32+
33+
public QuarkusDatasourceSupplier(
34+
RelationalJdbcConfiguration relationalJdbcConfiguration,
35+
List<InstanceHandle<DataSource>> dataSources) {
36+
this.relationalJdbcConfiguration = relationalJdbcConfiguration;
37+
this.dataSources = dataSources;
38+
}
39+
40+
@Override
41+
public DataSource fromRealmId(String realmId) {
42+
String dataSourceName =
43+
relationalJdbcConfiguration.datasource().getOrDefault(realmId, DEFAULT_DATA_SOURCE_NAME);
44+
for (InstanceHandle<DataSource> handle : dataSources) {
45+
String name = handle.getBean().getName();
46+
name = name == null ? DEFAULT_DATA_SOURCE_NAME : name;
47+
// if realm isolation is DB then there should be only one DS configured.
48+
if (name.equals(dataSourceName)) {
49+
return handle.get();
50+
}
51+
}
52+
throw new IllegalStateException("No datasource configured with name: " + realmId);
53+
}
54+
}

0 commit comments

Comments
 (0)