Skip to content
Open

wip #702

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
import com.netflix.metacat.common.server.connectors.ConnectorTableService;
import com.netflix.metacat.common.server.connectors.SpringConnectorFactory;
import com.netflix.metacat.connector.polaris.configs.PolarisConnectorConfig;
import com.netflix.metacat.connector.polaris.configs.PolarisDataSourceRegistry;
import com.netflix.metacat.connector.polaris.configs.PolarisPersistenceConfig;
import com.netflix.metacat.connector.polaris.configs.PolarisPersistenceReaderConfig;
import com.netflix.metacat.connector.polaris.configs.PolarisStoreConfig;
import org.springframework.core.env.MapPropertySource;

import javax.sql.DataSource;
import java.util.Collections;
import java.util.Map;

/**
* Connector Factory for Polaris.
Expand All @@ -36,6 +39,19 @@ class PolarisConnectorFactory extends SpringConnectorFactory {
PolarisPersistenceConfig.class,
PolarisPersistenceReaderConfig.class,
PolarisStoreConfig.class);

final Map<String, String> config = connectorContext.getConfiguration();
final String primaryUrl = config.get("spring.datasource.url");
if (primaryUrl != null) {
final DataSource shared = PolarisDataSourceRegistry.getOrCreatePrimary(primaryUrl, config);
ctx.getBeanFactory().registerSingleton("dataSource", shared);
}
final String readerUrl = config.get("spring.datasource.reader.url");
if (readerUrl != null) {
final DataSource shared = PolarisDataSourceRegistry.getOrCreateReader(readerUrl, config);
ctx.getBeanFactory().registerSingleton("readerDataSource", shared);
}

super.refresh();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
*
* Copyright 2021 Netflix, Inc.
*
* Licensed 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 com.netflix.metacat.connector.polaris.configs;

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;

import javax.sql.DataSource;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* JVM-scoped registry that ensures all Polaris catalogs pointing at the same database URL
* share a single HikariCP connection pool rather than creating one per catalog.
*
* Pools registered here are never destroyed by individual catalog context shutdowns.
*/
public final class PolarisDataSourceRegistry {

private static final ConcurrentHashMap<String, HikariDataSource> PRIMARY = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, HikariDataSource> READER = new ConcurrentHashMap<>();

private PolarisDataSourceRegistry() {
}

/**
* Returns a shared primary DataSource for the given URL, creating it on first call.
*
* @param url JDBC URL used as the cache key
* @param config flat property map from the connector context
* @return shared HikariDataSource
*/
public static DataSource getOrCreatePrimary(final String url, final Map<String, String> config) {
return PRIMARY.computeIfAbsent(url, k -> build(config, "spring.datasource"));
}

/**
* Returns a shared reader DataSource for the given URL, creating it on first call.
*
* @param url JDBC URL used as the cache key
* @param config flat property map from the connector context
* @return shared HikariDataSource
*/
public static DataSource getOrCreateReader(final String url, final Map<String, String> config) {
return READER.computeIfAbsent(url, k -> build(config, "spring.datasource.reader"));
}

private static HikariDataSource build(final Map<String, String> config, final String prefix) {
final StandardEnvironment env = new StandardEnvironment();
env.getPropertySources().addFirst(
new MapPropertySource("polaris_registry", Collections.unmodifiableMap(config)));
final Binder binder = Binder.get(env);

final DataSourceProperties props = binder
.bind(prefix, Bindable.of(DataSourceProperties.class))
.orElse(new DataSourceProperties());

final HikariDataSource ds = props.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();

binder.bind(prefix + ".hikari", Bindable.ofInstance(ds));
return ds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
Expand Down Expand Up @@ -44,6 +45,7 @@ public class PolarisPersistenceConfig {
*/
@Bean
@Primary
@ConditionalOnMissingBean(DataSource.class)
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public DataSource dataSource(final DataSourceProperties dataSourceProperties) {
return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
Expand All @@ -31,6 +32,7 @@ public class PolarisPersistenceReaderConfig {
* @return a configured DataSource instance.
*/
@Bean
@ConditionalOnMissingBean(name = "readerDataSource")
@ConfigurationProperties(prefix = "spring.datasource.reader.hikari")
public DataSource readerDataSource(@Qualifier("readerDataSourceProperties")
final DataSourceProperties readerDataSourceProperties) {
Expand Down
Loading