dremio jdbc arp 扩展包装以及加载处理
如果按照官方直接提供的jdbc 存储插件进行jdbc驱动开发是很痛苦的,好多问题需要解决
还好官方抽象了arp 开发模式,大大简化了我们的处理,而且很灵活,很简单
参考处理
- 创建调用链
以下是一个添加arp 的处理流程
stack com.dremio.exec.store.jdbc.conf.JdbcConf newPlugin
Press Q or Ctrl+C to abort.
Affect(class count: 8 , method count: 2) cost in 370 ms, listenerId: 2
ts=2022-03-03 13:44:05;thread_name=qtp114593564-209;id=d1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2
@com.dremio.exec.store.jdbc.conf.JdbcConf.newPlugin()
at com.dremio.exec.catalog.ManagedStoragePlugin.<init>(ManagedStoragePlugin.java:163)
at com.dremio.exec.catalog.PluginsManager.newManagedStoragePlugin(PluginsManager.java:282)
at com.dremio.exec.catalog.PluginsManager.newPlugin(PluginsManager.java:268)
at com.dremio.exec.catalog.PluginsManager.create(PluginsManager.java:168)
at com.dremio.exec.catalog.CatalogServiceImpl.createSource(CatalogServiceImpl.java:418)
at com.dremio.exec.catalog.CatalogServiceImpl.access$400(CatalogServiceImpl.java:106)
at com.dremio.exec.catalog.CatalogServiceImpl$SourceModifier.createSource(CatalogServiceImpl.java:751)
at com.dremio.exec.catalog.CatalogImpl.createSource(CatalogImpl.java:1104)
at com.dremio.exec.catalog.SourceAccessChecker.createSource(SourceAccessChecker.java:309)
at com.dremio.exec.catalog.DelegatingCatalog.createSource(DelegatingCatalog.java:277)
at com.dremio.dac.service.source.SourceService.registerSourceWithRuntime(SourceService.java:162)
at com.dremio.dac.service.source.SourceService.registerSourceWithRuntime(SourceService.java:153)
at com.dremio.dac.service.source.SourceService.registerSourceWithRuntime(SourceService.java:149)
at com.dremio.dac.resource.PutSourceResource.putSource(PutSourceResource.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:52)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:124)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:167)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:219)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:79)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:469)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:391)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:80)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:253)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:248)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:244)
at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
at org.glassfish.jersey.internal.Errors.process(Errors.java:244)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:232)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:680)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:394)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:346)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:366)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:319)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:205)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1626)
at com.dremio.dac.server.GenericResponseHeadersFilter.doFilter(GenericResponseHeadersFilter.java:46)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at com.dremio.dac.server.SecurityHeadersFilter.doFilter(SecurityHeadersFilter.java:69)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1434)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:713)
at org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:54)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:386)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.lang.Thread.run(Thread.java:750)
- arp 扩展处理
JdbcConf 抽象类,我们实际扩展的是AbstractArpConf
public abstract class JdbcConf<T extends DialectConf<T, JdbcStoragePlugin>> extends DialectConf<T, JdbcStoragePlugin> {
private static final Logger logger = LoggerFactory.getLogger(JdbcConf.class);
public JdbcConf() {
}
// 抽象方法,简化arp开发, 包含了三个参数,JdbcPluginConfig builder ,CredentialsService 主要是特定的,目前主要看到了aws 的
OptionManager 是一个配置管理,可以获取系统配置参数
public abstract JdbcPluginConfig buildPluginConfig(Builder var1, CredentialsService var2, OptionManager var3);
public JdbcStoragePlugin newPlugin(SabotContext context, String name, Provider<StoragePluginId> pluginIdProvider) {
JdbcSchemaFetcherFactory factory = JdbcSchemaFetcherFactory.of(context.getConfig(), context.getJdbcSchemaFetcherFactoryContext());
logger.debug("Plugin {} is using fetcher factory: {}", name, factory.getClass());
JdbcSchemaFetcher schemaFetcher = factory.newFetcher(name, this);
// 基于配置创建jdbc 存储插件
return new JdbcStoragePlugin(schemaFetcher.getConfig(), schemaFetcher, context.getConfig(), pluginIdProvider, context.getOptionManager().getOption(PlannerSettings.FULL_NESTED_SCHEMA_SUPPORT));
}
}
AbstractArpConf 定义
public abstract class AbstractArpConf<T extends JdbcConf<T>> extends JdbcConf<T> {
private static final Logger logger = LoggerFactory.getLogger(AbstractArpConf.class);
public AbstractArpConf() {
}
protected static <T extends ArpDialect> T loadArpFile(String pathToArpFile, Function<ArpYaml, T> dialectConstructor) {
ArpDialect dialect;
try {
ArpYaml yaml = ArpYaml.createFromFile(pathToArpFile);
dialect = (ArpDialect)dialectConstructor.apply(yaml);
} catch (Exception var4) {
dialect = null;
logger.error("Error creating dialect from ARP file {}.", pathToArpFile, var4);
}
return dialect;
}
}
arp 机制
实际上dremio 实现了一个自己的插件管理器PluginsManager ,插件管理器是在
sabot/kernel/src/main/java/com/dremio/exec/catalog/CatalogServiceImpl.java 实现中创建的
创建方法(CatalogServiceImpl start 中创建的)
protected PluginsManager newPluginsManager() {
return new PluginsManager(context.get(), systemNamespace, datasetListingService.get(), optionManager.get(),
config, sourceDataStore, scheduler.get(), connectionReaderProvider.get(), monitor, broadcasterProvider,
isInfluxSource, modifiableSchedulerService);
}
PluginsManager 方法
PluginsManager 的create 方法会返回一个ManagedStoragePlugin,ManagedStoragePlugin 进行arp 扩展的创建加载,ManagedStoragePlugin 对象
的构造函数会创建arp 插件(可以结合上边的调用链查看)
sabot/kernel/src/main/java/com/dremio/exec/catalog/ManagedStoragePlugin.java
public ManagedStoragePlugin(
SabotContext context,
Executor executor,
boolean isMaster,
ModifiableSchedulerService modifiableScheduler,
NamespaceService systemUserNamespaceService,
LegacyKVStore<NamespaceKey, SourceInternalData> sourceDataStore,
SourceConfig sourceConfig,
OptionManager options,
ConnectionReader reader,
CatalogServiceMonitor monitor,
Provider<MetadataRefreshInfoBroadcaster> broadcasterProvider
) {
this.rwlock = new ReentrantReadWriteLock(true);
this.executor = executor;
this.readLock = rwlock.readLock();
this.writeLock = rwlock.writeLock();
this.context = context;
this.sourceConfig = sourceConfig;
this.sourceKey = new NamespaceKey(sourceConfig.getName());
this.name = sourceConfig.getName();
this.systemUserNamespaceService = systemUserNamespaceService;
// reader 是比较重要的,包含了一个默认实现ConnectionReaderImpl,基于bean 注入
this.conf = reader.getConnectionConf(sourceConfig);
// 此处创建jdbc 存储扩展
this.plugin = conf.newPlugin(context, sourceConfig.getName(), this::getId);
this.metadataPolicy = sourceConfig.getMetadataPolicy() == null ? CatalogService.NEVER_REFRESH_POLICY : sourceConfig.getMetadataPolicy();
this.permissionsCache = new PermissionCheckCache(this::getPlugin, () -> getMetadataPolicy().getAuthTtlMs(), 2500);
this.options = options;
this.reader = reader;
this.monitor = monitor;
fixFailedThread = new FixFailedToStart();
// leaks this so do last.
this.metadataManager = new SourceMetadataManager(
sourceKey,
modifiableScheduler,
isMaster,
sourceDataStore,
new MetadataBridge(),
options,
monitor,
broadcasterProvider);
}
说明
jdbc arp 的加载实际上是一种先创建,在使用的模式,加载处理上并没有太多的难度,主要是dremio 的包装比价方便,比较灵活,实际上还包含
jdbc 存储插件的配置存储,上边没有介绍,可以结合源码学习