Compare commits

...

50 Commits

Author SHA1 Message Date
agapple
64862503ba [maven-release-plugin] prepare release canal-1.1.5 2021-04-19 15:48:09 +08:00
agapple
f9e0dc7daa fixed testcase 2021-04-19 15:15:10 +08:00
agapple
0c399509a9 upgrade druid 1.2.6 2021-04-19 12:57:21 +08:00
agapple
a09cd9adb5 fixed issue #3110 , json escapse 2021-04-19 11:28:45 +08:00
agapple
1369418c6a fixed code format & merge 2021-04-19 10:55:43 +08:00
995586041
75174a63af 增加rabbitmq消息持久化deliveryMode配置 (#3300) 2021-04-19 10:29:23 +08:00
zoemak
17f4ee13e7 自动注册时可自定义node server名称,canal.properties#canal.admin.register.name,为空则使用canal.register.ip (#3459) 2021-04-19 10:18:01 +08:00
Fei Yang
f0417502f8 fix: unit_present typo (#3461)
https://github.com/alibaba/canal/issues/3434
2021-04-19 10:16:17 +08:00
renyansongno1
a7720b51e4 支持rocketmq的消息按照tag去发送 (#3438)
* 支持rocketmq的消息按照tag去发送
并对应修改了配置文件

* 将tag的设计转移到Rocketmq的单独配置项
2021-04-19 10:14:27 +08:00
suman-lee
21904ef1dc 基于明确的I/U/D是否过滤 (#3452)
* dmls filter

* dmls filters

* 基于明确的I/U/D是否过滤

* 基于明确的I/U/D是否过滤
2021-04-19 10:10:54 +08:00
agapple
94425223bd fixed issue #3454 , concurrent env bugfix 2021-04-17 10:57:25 +08:00
agapple
7857df9701 add sql parser testcase 2021-04-17 10:49:17 +08:00
agapple
64ea4ff222 fixed issue #3267 , fixed rockemq send null message 2021-04-17 10:25:49 +08:00
agapple
85df89f777 fixed issue #3377 , escapse schema name 2021-04-16 23:11:41 +08:00
AlphaKitty
a0f8e182ec 修复当host中存在冒号(比如https:)抛UnknownHostException问题 (#3223)
* 修复当host中存在冒号(比如https:)抛UnknownHostException问题

* 更优雅地解析url
2021-04-16 22:11:21 +08:00
温绍锦
33721d0394 update druid version (#3146)
* replace fastsql with druid

* update druid version
2021-04-16 22:09:40 +08:00
Treeyh
91bddfeed6 修复接入阿里云RocketMq no route info for this topic 问题 (#3220)
Co-authored-by: hai.yu <hai.yu@snowballtech.com>
2021-04-16 22:08:28 +08:00
16075140
25feab4af8 support rabbitmq port by config (#3236) 2021-04-16 22:07:12 +08:00
binbin
f66baeabf1 修复最近位置被remove掉,导致重复消息的问题 (#3276) 2021-04-16 22:03:51 +08:00
agapple
b1dc3821ea fixed config url auth 2021-04-16 21:52:23 +08:00
Jump-Boy
f5f79104eb fix centos 6.10 yum bug and update jdk8.rpm download url (#3398) 2021-04-16 21:41:55 +08:00
ltamber
e8d138d3bd fix: uuidset combine fix (#3432) 2021-04-16 21:37:55 +08:00
zoemak
32d9e58915 升级rocketmq到4.8.0,并且支持环境变量优先配置 (#3450) 2021-04-16 21:35:11 +08:00
许道杰
58448e559d fix: issue #2649 client-adapter启动时抛LinkageError异常、#3073 client-adapter通过启动参数传入canal.tcp.zookeeper.hosts为空值时抛异常 (#3074) 2021-04-16 21:25:14 +08:00
许道杰
fede3b3d1d fix #3126 将hbase-client依赖修改为hbase-shaded-client (#3127) 2021-04-16 21:24:44 +08:00
许道杰
5d8ec31bc4 fix #3119 (#3121) 2021-04-16 21:22:31 +08:00
WangCong
82b18ebe62 feat unsigned bug (#3104) 2021-04-16 21:17:43 +08:00
hupeng
66408782b0 process()方法中,在retry循环中处理成功应该break (#3080)
process()方法中,在retry循环中处理成功应该break
2021-04-16 21:14:43 +08:00
许道杰
846c8870ae fix: issue #3076 (#3077) 2021-04-16 21:12:12 +08:00
ljcoder
8cfb07f07e 数据库名称如何存在中划线"-"情况下,SQL执行异常 (#3228)
Co-authored-by: liguowang <liguowang@aerozhonghaun.com>
2020-12-31 11:33:01 +08:00
文哥
d741425895 升级guava 至 22.0 (#3184)
* fix issue:#561 增加一个外部参数控制,允许位点不存在时自动重置到当前位点

* Add MariaDB GTID support

* remove client pom bad ns

* upgrade guava version to 22.0
2020-11-20 13:47:26 +08:00
文哥
20add85ff6 统一Canal 依赖的Spring 版本,升级ibatis 至mybatis (#3182)
* fix issue:#561 增加一个外部参数控制,允许位点不存在时自动重置到当前位点

* Add MariaDB GTID support

* 1. fix maven central repository url access error.(Update to https)
2. upgrade spring version to 5.0.5.RELEASE
3. upgrade ibatis to mybatis

* fix unit test run error
2020-11-20 09:24:56 +08:00
agapple
a5c09c521e Update README.md 2020-11-02 12:54:54 +08:00
agapple
c94276b1ac Update README.md 2020-11-02 12:53:35 +08:00
agapple
272d575c78 Update README.md 2020-11-02 12:44:59 +08:00
温绍锦
693f8d501a replace fastsql with druid (#3132) 2020-10-31 13:19:03 +08:00
温绍锦
bb1b6b9862 Update README.md 2020-10-23 14:41:31 +08:00
温绍锦
8ed82caaef Update README.md 2020-09-29 16:18:23 +08:00
文哥
de1dd70609 1. Add MariaDB gtid support 2. fix issue:#561 增加一个外部参数控制,允许位点不存在时自动重置到当前位点 (#3025)
* fix issue:#561 增加一个外部参数控制,允许位点不存在时自动重置到当前位点

* Add MariaDB GTID support
2020-09-24 17:56:40 +08:00
zavakid
09429c241f = inner class MessageEventFactory to be static 2020-09-23 11:37:17 +08:00
zavakid
9a332940d7 = remove unused import 2020-09-23 11:34:45 +08:00
zavakid
362974b1c2 = code cleanup: remove unnessary boxing 2020-09-18 00:54:23 +08:00
zavakid
435db30b7b = performance improve
- using bulk operation instead of iteration if possible
  - terminate loop after condition is met
2020-09-18 00:51:53 +08:00
zavakid
e7de8289cd = code cleanup : modified inner class to 'static' if possible 2020-09-18 00:49:48 +08:00
zavakid
5065fea963 = fix BooleanMutex's inner Sync to static class and add test case 2020-09-18 00:44:25 +08:00
zavakid
6989eb3d2b + fix logging call placeholders number 2020-09-17 23:26:02 +08:00
zavakid
df24596092 = code cleanup
- for loop replaceable with enhanced 'for' loop
  - using diamond in generic type
  - collapse try catch exception
  - using try-with-resource
  - using  List#sort instead of Collections#sort
  - replaced lambda with method reference
  - using native compare method to compare numbers
  - using switch instead of if for in ESSyncUtil
2020-09-17 23:22:25 +08:00
zavakid
43c23ffb97 = remove unused improt 2020-09-17 22:40:06 +08:00
zavakid
e7658879bc = cold cleanup
* using lambda if possible (we are already building in Java8)
  * using diamond when new generic instance
  * remove used improt
2020-09-17 17:46:20 +08:00
zavakid
df60eda679 = code cleanup 2020-09-16 14:18:05 +08:00
265 changed files with 2746 additions and 2630 deletions

View File

@@ -90,10 +90,13 @@ canal 作为 MySQL binlog 增量获取和解析工具,可将变更记录投递
- 参考文档: [Canal Kafka/RocketMQ QuickStart](https://github.com/alibaba/canal/wiki/Canal-Kafka-RocketMQ-QuickStart) - 参考文档: [Canal Kafka/RocketMQ QuickStart](https://github.com/alibaba/canal/wiki/Canal-Kafka-RocketMQ-QuickStart)
## 相关开源 ## 相关开源&产品
- [canal 消费端开源项目: Otter](http://github.com/alibaba/otter) - [canal 消费端开源项目: Otter](http://github.com/alibaba/otter)
- [阿里巴巴去 Oracle 数据迁移同步工具: yugong](http://github.com/alibaba/yugong) - [阿里巴巴去 Oracle 数据迁移同步工具: yugong](http://github.com/alibaba/yugong)
- [阿里巴巴离线同步开源项目 DataX](https://github.com/alibaba/datax)
- [阿里巴巴数据库连接池开源项目 Druid](https://github.com/alibaba/druid)
- [阿里巴巴实时数据同步工具 DTS](https://www.aliyun.com/product/dts)
## 问题反馈 ## 问题反馈
- 报告 issue: [github issues](https://github.com/alibaba/canal/issues) - 报告 issue: [github issues](https://github.com/alibaba/canal/issues)

View File

@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>canal.admin</artifactId> <artifactId>canal.admin</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>canal.admin</artifactId> <artifactId>canal.admin</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>canal.admin-web</artifactId> <artifactId>canal.admin-web</artifactId>

View File

@@ -1,5 +1,13 @@
#!/bin/bash #!/bin/bash
sh stop.sh case $(uname) in
Linux)
bin_abs_path=$(readlink -f $(dirname $0))
;;
*)
bin_abs_path=$(cd $(dirname $0) ||exit ; pwd)
;;
esac
sh startup.sh sh "$bin_abs_path"/stop.sh
sh "$bin_abs_path"/startup.sh

View File

@@ -12,6 +12,6 @@ public class Threads {
pool, pool,
0L, 0L,
TimeUnit.MILLISECONDS, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(pool * 20), new ArrayBlockingQueue<>(pool * 20),
DaemonThreadFactory.daemonThreadFactory); DaemonThreadFactory.daemonThreadFactory);
} }

View File

@@ -84,7 +84,9 @@ public class WebConfig implements WebMvcConfigurer {
} }
}) })
.addPathPatterns("/api/**") .addPathPatterns("/api/**")
.excludePathPatterns("/api/**/config/**") .excludePathPatterns("/api/**/config/server_polling")
.excludePathPatterns("/api/**/config/instances_polling")
.excludePathPatterns("/api/**/config/instance_polling/**")
.excludePathPatterns("/api/**/user/login") .excludePathPatterns("/api/**/user/login")
.excludePathPatterns("/api/**/user/logout") .excludePathPatterns("/api/**/user/logout")
.excludePathPatterns("/api/**/user/info"); .excludePathPatterns("/api/**/user/info");

View File

@@ -108,9 +108,7 @@ public class SimpleAdminConnector implements AdminConnector {
} }
connected = true; connected = true;
} catch (IOException e) { } catch (IOException | NoSuchAlgorithmException e) {
throw new ServiceException(e);
} catch (NoSuchAlgorithmException e) {
throw new ServiceException(e); throw new ServiceException(e);
} }
} }

View File

@@ -46,14 +46,15 @@ public class PollingConfigController {
public BaseModel<CanalConfig> canalConfigPoll(@RequestHeader String user, @RequestHeader String passwd, public BaseModel<CanalConfig> canalConfigPoll(@RequestHeader String user, @RequestHeader String passwd,
@RequestParam String ip, @RequestParam Integer port, @RequestParam String ip, @RequestParam Integer port,
@RequestParam String md5, @RequestParam boolean register, @RequestParam String md5, @RequestParam boolean register,
@RequestParam String cluster, @PathVariable String env) { @RequestParam String cluster, @RequestParam String name,
@PathVariable String env) {
if (!auth(user, passwd)) { if (!auth(user, passwd)) {
throw new RuntimeException("auth :" + user + " is failed"); throw new RuntimeException("auth :" + user + " is failed");
} }
if (StringUtils.isEmpty(md5) && register) { if (StringUtils.isEmpty(md5) && register) {
// do something // do something
pollingConfigService.autoRegister(ip, port, cluster); pollingConfigService.autoRegister(ip, port, cluster, StringUtils.trimToNull(name));
} }
CanalConfig canalConfig = pollingConfigService.getChangedConfig(ip, port, md5); CanalConfig canalConfig = pollingConfigService.getChangedConfig(ip, port, md5);

View File

@@ -9,7 +9,7 @@ public class Pager<T> implements Serializable {
private static final long serialVersionUID = -986577815091763517L; private static final long serialVersionUID = -986577815091763517L;
private Long count = 0L; private Long count = 0L;
private List<T> items = new ArrayList<T>(); private List<T> items = new ArrayList<>();
private Integer page = 1; private Integer page = 1;
private Integer size = 20; private Integer size = 20;
private Long offset = 0L; private Long offset = 0L;

View File

@@ -5,7 +5,7 @@ import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
public interface PollingConfigService { public interface PollingConfigService {
public boolean autoRegister(String ip, Integer adminPort, String cluster); public boolean autoRegister(String ip, Integer adminPort, String cluster, String name);
CanalConfig getChangedConfig(String ip, Integer port, String md5); CanalConfig getChangedConfig(String ip, Integer port, String md5);

View File

@@ -2,6 +2,7 @@ package com.alibaba.otter.canal.admin.service.impl;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@@ -28,11 +29,11 @@ public class PollingConfigServiceImpl implements PollingConfigService {
@Autowired @Autowired
CanalClusterService canalClusterService; CanalClusterService canalClusterService;
public boolean autoRegister(String ip, Integer adminPort, String cluster) { public boolean autoRegister(String ip, Integer adminPort, String cluster, String name) {
NodeServer server = NodeServer.find.query().where().eq("ip", ip).eq("adminPort", adminPort).findOne(); NodeServer server = NodeServer.find.query().where().eq("ip", ip).eq("adminPort", adminPort).findOne();
if (server == null) { if (server == null) {
server = new NodeServer(); server = new NodeServer();
server.setName(ip); server.setName(Optional.ofNullable(name).orElse(ip));
server.setIp(ip); server.setIp(ip);
server.setAdminPort(adminPort); server.setAdminPort(adminPort);
server.setTcpPort(adminPort + 1); server.setTcpPort(adminPort + 1);

View File

@@ -16,6 +16,10 @@ canal.metrics.pull.port = 11112
canal.admin.port = 11110 canal.admin.port = 11110
canal.admin.user = admin canal.admin.user = admin
canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441 canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441
# admin auto register
#canal.admin.register.auto = true
#canal.admin.register.cluster =
#canal.admin.register.name =
canal.zkServers = canal.zkServers =
# flush data to zk # flush data to zk
@@ -60,6 +64,9 @@ canal.instance.filter.query.ddl = false
canal.instance.filter.table.error = false canal.instance.filter.table.error = false
canal.instance.filter.rows = false canal.instance.filter.rows = false
canal.instance.filter.transaction.entry = false canal.instance.filter.transaction.entry = false
canal.instance.filter.dml.insert = false
canal.instance.filter.dml.update = false
canal.instance.filter.dml.delete = false
# binlog format/image check # binlog format/image check
canal.instance.binlog.format = ROW,STATEMENT,MIXED canal.instance.binlog.format = ROW,STATEMENT,MIXED
@@ -95,6 +102,9 @@ canal.conf.dir = ../conf
# auto scan instance dir add/remove and start/stop instance # auto scan instance dir add/remove and start/stop instance
canal.auto.scan = true canal.auto.scan = true
canal.auto.scan.interval = 5 canal.auto.scan.interval = 5
# set this value to 'true' means that when binlog pos not found, skip to latest.
# WARN: pls keep 'false' in production env, or if you know what you want.
canal.auto.reset.latest.pos.mode = false
canal.instance.tsdb.spring.xml = classpath:spring/tsdb/h2-tsdb.xml canal.instance.tsdb.spring.xml = classpath:spring/tsdb/h2-tsdb.xml
#canal.instance.tsdb.spring.xml = classpath:spring/tsdb/mysql-tsdb.xml #canal.instance.tsdb.spring.xml = classpath:spring/tsdb/mysql-tsdb.xml
@@ -151,6 +161,7 @@ rocketmq.namespace =
rocketmq.namesrv.addr = 127.0.0.1:9876 rocketmq.namesrv.addr = 127.0.0.1:9876
rocketmq.retry.times.when.send.failed = 0 rocketmq.retry.times.when.send.failed = 0
rocketmq.vip.channel.enabled = false rocketmq.vip.channel.enabled = false
rocketmq.tag =
################################################## ##################################################
######### RabbitMQ ############# ######### RabbitMQ #############
@@ -159,4 +170,5 @@ rabbitmq.host =
rabbitmq.virtual.host = rabbitmq.virtual.host =
rabbitmq.exchange = rabbitmq.exchange =
rabbitmq.username = rabbitmq.username =
rabbitmq.password = rabbitmq.password =
rabbitmq.deliveryMode =

View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<artifactId>canal.admin</artifactId> <artifactId>canal.admin</artifactId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>canal admin module for otter ${project.version}</name> <name>canal admin module for otter ${project.version}</name>
<modules> <modules>

View File

@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -140,7 +140,7 @@ public class YmlConfigBinder {
MutablePropertySources propertySources = new MutablePropertySources(); MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(propertySource); propertySources.addFirst(propertySource);
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(target); PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<>(target);
factory.setPropertySources(propertySources); factory.setPropertySources(propertySources);
factory.setIgnoreInvalidFields(true); factory.setIgnoreInvalidFields(true);
factory.setIgnoreUnknownFields(true); factory.setIgnoreUnknownFields(true);

View File

@@ -25,7 +25,7 @@ class DefaultPropertyNamePatternsMatcher implements PropertyNamePatternsMatcher
} }
protected DefaultPropertyNamePatternsMatcher(char[] delimiters, boolean ignoreCase, String... names){ protected DefaultPropertyNamePatternsMatcher(char[] delimiters, boolean ignoreCase, String... names){
this(delimiters, ignoreCase, new HashSet<String>(Arrays.asList(names))); this(delimiters, ignoreCase, new HashSet<>(Arrays.asList(names)));
} }
DefaultPropertyNamePatternsMatcher(char[] delimiters, boolean ignoreCase, Set<String> names){ DefaultPropertyNamePatternsMatcher(char[] delimiters, boolean ignoreCase, Set<String> names){
@@ -70,8 +70,8 @@ class DefaultPropertyNamePatternsMatcher implements PropertyNamePatternsMatcher
return false; return false;
} }
} }
for (int i = 0; i < match.length; i++) { for (boolean b : match) {
if (match[i]) { if (b) {
return true; return true;
} }
} }

View File

@@ -277,7 +277,7 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>, Applic
} }
private Set<String> getNames(Iterable<String> prefixes) { private Set<String> getNames(Iterable<String> prefixes) {
Set<String> names = new LinkedHashSet<String>(); Set<String> names = new LinkedHashSet<>();
if (this.target != null) { if (this.target != null) {
PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(this.target.getClass()); PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(this.target.getClass());
for (PropertyDescriptor descriptor : descriptors) { for (PropertyDescriptor descriptor : descriptors) {
@@ -318,7 +318,7 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>, Applic
// We can filter properties to those starting with the target name, but // We can filter properties to those starting with the target name, but
// we can't do a complete filter since we need to trigger the // we can't do a complete filter since we need to trigger the
// unknown fields check // unknown fields check
Set<String> relaxedNames = new HashSet<String>(); Set<String> relaxedNames = new HashSet<>();
for (String relaxedTargetName : relaxedTargetNames) { for (String relaxedTargetName : relaxedTargetNames) {
relaxedNames.add(relaxedTargetName); relaxedNames.add(relaxedTargetName);
} }

View File

@@ -9,23 +9,9 @@ package com.alibaba.otter.canal.client.adapter.config.bind;
*/ */
interface PropertyNamePatternsMatcher { interface PropertyNamePatternsMatcher {
PropertyNamePatternsMatcher ALL = new PropertyNamePatternsMatcher() { PropertyNamePatternsMatcher ALL = propertyName -> true;
@Override PropertyNamePatternsMatcher NONE = propertyName -> false;
public boolean matches(String propertyName) {
return true;
}
};
PropertyNamePatternsMatcher NONE = new PropertyNamePatternsMatcher() {
@Override
public boolean matches(String propertyName) {
return false;
}
};
/** /**
* Return {@code true} of the property name matches. * Return {@code true} of the property name matches.

View File

@@ -37,9 +37,9 @@ public class PropertySourcesPropertyValues implements PropertyValues {
private final PropertyNamePatternsMatcher includes; private final PropertyNamePatternsMatcher includes;
private final Map<String, PropertyValue> propertyValues = new LinkedHashMap<String, PropertyValue>(); private final Map<String, PropertyValue> propertyValues = new LinkedHashMap<>();
private final ConcurrentHashMap<String, PropertySource<?>> collectionOwners = new ConcurrentHashMap<String, PropertySource<?>>(); private final ConcurrentHashMap<String, PropertySource<?>> collectionOwners = new ConcurrentHashMap<>();
private final boolean resolvePlaceholders; private final boolean resolvePlaceholders;

View File

@@ -32,7 +32,7 @@ public class RelaxedDataBinder extends DataBinder {
private static final Set<Class<?>> EXCLUDED_EDITORS; private static final Set<Class<?>> EXCLUDED_EDITORS;
static { static {
Set<Class<?>> excluded = new HashSet<Class<?>>(); Set<Class<?>> excluded = new HashSet<>();
excluded.add(FileEditor.class); excluded.add(FileEditor.class);
EXCLUDED_EDITORS = Collections.unmodifiableSet(excluded); EXCLUDED_EDITORS = Collections.unmodifiableSet(excluded);
} }
@@ -43,7 +43,7 @@ public class RelaxedDataBinder extends DataBinder {
private boolean ignoreNestedProperties; private boolean ignoreNestedProperties;
private MultiValueMap<String, String> nameAliases = new LinkedMultiValueMap<String, String>(); private MultiValueMap<String, String> nameAliases = new LinkedMultiValueMap<>();
/** /**
* Create a new {@link RelaxedDataBinder} instance. * Create a new {@link RelaxedDataBinder} instance.
@@ -89,7 +89,7 @@ public class RelaxedDataBinder extends DataBinder {
* @param aliases a map of property name to aliases * @param aliases a map of property name to aliases
*/ */
public void setNameAliases(Map<String, List<String>> aliases) { public void setNameAliases(Map<String, List<String>> aliases) {
this.nameAliases = new LinkedMultiValueMap<String, String>(aliases); this.nameAliases = new LinkedMultiValueMap<>(aliases);
} }
/** /**
@@ -129,8 +129,8 @@ public class RelaxedDataBinder extends DataBinder {
BeanWrapper wrapper = new BeanWrapperImpl(target); BeanWrapper wrapper = new BeanWrapperImpl(target);
wrapper.setConversionService(new RelaxedConversionService(getConversionService())); wrapper.setConversionService(new RelaxedConversionService(getConversionService()));
wrapper.setAutoGrowNestedPaths(true); wrapper.setAutoGrowNestedPaths(true);
List<PropertyValue> sortedValues = new ArrayList<PropertyValue>(); List<PropertyValue> sortedValues = new ArrayList<>();
Set<String> modifiedNames = new HashSet<String>(); Set<String> modifiedNames = new HashSet<>();
List<String> sortedNames = getSortedPropertyNames(propertyValues); List<String> sortedNames = getSortedPropertyNames(propertyValues);
for (String name : sortedNames) { for (String name : sortedNames) {
PropertyValue propertyValue = propertyValues.getPropertyValue(name); PropertyValue propertyValue = propertyValues.getPropertyValue(name);
@@ -143,7 +143,7 @@ public class RelaxedDataBinder extends DataBinder {
} }
private List<String> getSortedPropertyNames(MutablePropertyValues propertyValues) { private List<String> getSortedPropertyNames(MutablePropertyValues propertyValues) {
List<String> names = new LinkedList<String>(); List<String> names = new LinkedList<>();
for (PropertyValue propertyValue : propertyValues.getPropertyValueList()) { for (PropertyValue propertyValue : propertyValues.getPropertyValueList()) {
names.add(propertyValue.getName()); names.add(propertyValue.getName());
} }
@@ -161,7 +161,7 @@ public class RelaxedDataBinder extends DataBinder {
* @param names the names to sort * @param names the names to sort
*/ */
private void sortPropertyNames(List<String> names) { private void sortPropertyNames(List<String> names) {
for (String name : new ArrayList<String>(names)) { for (String name : new ArrayList<>(names)) {
int propertyIndex = names.indexOf(name); int propertyIndex = names.indexOf(name);
RelaxedDataBinder.BeanPath path = new RelaxedDataBinder.BeanPath(name); RelaxedDataBinder.BeanPath path = new RelaxedDataBinder.BeanPath(name);
for (String prefix : path.prefixes()) { for (String prefix : path.prefixes()) {
@@ -319,7 +319,7 @@ public class RelaxedDataBinder extends DataBinder {
} }
Object extend = new LinkedHashMap<String, Object>(); Object extend = new LinkedHashMap<String, Object>();
if (!elementDescriptor.isMap() && path.isArrayIndex(index)) { if (!elementDescriptor.isMap() && path.isArrayIndex(index)) {
extend = new ArrayList<Object>(); extend = new ArrayList<>();
} }
wrapper.setPropertyValue(path.prefix(index + 1), extend); wrapper.setPropertyValue(path.prefix(index + 1), extend);
} }
@@ -347,7 +347,7 @@ public class RelaxedDataBinder extends DataBinder {
} }
Object extend = new LinkedHashMap<String, Object>(); Object extend = new LinkedHashMap<String, Object>();
if (descriptor.isCollection()) { if (descriptor.isCollection()) {
extend = new ArrayList<Object>(); extend = new ArrayList<>();
} }
if (descriptor.getType().equals(Object.class) && path.isLastNode(index)) { if (descriptor.getType().equals(Object.class) && path.isLastNode(index)) {
extend = BLANK; extend = BLANK;
@@ -411,7 +411,7 @@ public class RelaxedDataBinder extends DataBinder {
if (aliases == null) { if (aliases == null) {
return Collections.singleton(name); return Collections.singleton(name);
} }
List<String> nameAndAliases = new ArrayList<String>(aliases.size() + 1); List<String> nameAndAliases = new ArrayList<>(aliases.size() + 1);
nameAndAliases.add(name); nameAndAliases.add(name);
nameAndAliases.addAll(aliases); nameAndAliases.addAll(aliases);
return nameAndAliases; return nameAndAliases;
@@ -473,7 +473,7 @@ public class RelaxedDataBinder extends DataBinder {
} }
public List<String> prefixes() { public List<String> prefixes() {
List<String> prefixes = new ArrayList<String>(); List<String> prefixes = new ArrayList<>();
for (int index = 1; index < this.nodes.size(); index++) { for (int index = 1; index < this.nodes.size(); index++) {
prefixes.add(prefix(index)); prefixes.add(prefix(index));
} }
@@ -485,7 +485,7 @@ public class RelaxedDataBinder extends DataBinder {
} }
private List<PathNode> splitPath(String path) { private List<PathNode> splitPath(String path) {
List<PathNode> nodes = new ArrayList<PathNode>(); List<PathNode> nodes = new ArrayList<>();
String current = extractIndexedPaths(path, nodes); String current = extractIndexedPaths(path, nodes);
for (String name : StringUtils.delimitedListToStringArray(current, ".")) { for (String name : StringUtils.delimitedListToStringArray(current, ".")) {
if (StringUtils.hasText(name)) { if (StringUtils.hasText(name)) {
@@ -518,7 +518,7 @@ public class RelaxedDataBinder extends DataBinder {
} }
public void collapseKeys(int index) { public void collapseKeys(int index) {
List<PathNode> revised = new ArrayList<PathNode>(); List<PathNode> revised = new ArrayList<>();
for (int i = 0; i < index; i++) { for (int i = 0; i < index; i++) {
revised.add(this.nodes.get(i)); revised.add(this.nodes.get(i));
} }
@@ -668,7 +668,7 @@ public class RelaxedDataBinder extends DataBinder {
private static final Set<String> BENIGN_PROPERTY_SOURCE_NAMES; private static final Set<String> BENIGN_PROPERTY_SOURCE_NAMES;
static { static {
Set<String> names = new HashSet<String>(); Set<String> names = new HashSet<>();
names.add(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); names.add(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
names.add(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME); names.add(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);
BENIGN_PROPERTY_SOURCE_NAMES = Collections.unmodifiableSet(names); BENIGN_PROPERTY_SOURCE_NAMES = Collections.unmodifiableSet(names);

View File

@@ -24,7 +24,7 @@ public final class RelaxedNames implements Iterable<String> {
private final String name; private final String name;
private final Set<String> values = new LinkedHashSet<String>(); private final Set<String> values = new LinkedHashSet<>();
/** /**
* Create a new {@link RelaxedNames} instance. * Create a new {@link RelaxedNames} instance.

View File

@@ -22,7 +22,7 @@ import org.springframework.util.StringUtils;
*/ */
public class CompositePropertySource extends EnumerablePropertySource<Object> { public class CompositePropertySource extends EnumerablePropertySource<Object> {
private final Set<PropertySource<?>> propertySources = new LinkedHashSet<PropertySource<?>>(); private final Set<PropertySource<?>> propertySources = new LinkedHashSet<>();
/** /**
* Create a new {@code CompositePropertySource}. * Create a new {@code CompositePropertySource}.
@@ -56,7 +56,7 @@ public class CompositePropertySource extends EnumerablePropertySource<Object> {
@Override @Override
public String[] getPropertyNames() { public String[] getPropertyNames() {
Set<String> names = new LinkedHashSet<String>(); Set<String> names = new LinkedHashSet<>();
for (PropertySource<?> propertySource : this.propertySources) { for (PropertySource<?> propertySource : this.propertySources) {
if (!(propertySource instanceof EnumerablePropertySource)) { if (!(propertySource instanceof EnumerablePropertySource)) {
throw new IllegalStateException( throw new IllegalStateException(
@@ -83,7 +83,7 @@ public class CompositePropertySource extends EnumerablePropertySource<Object> {
* @since 4.1 * @since 4.1
*/ */
public void addFirstPropertySource(PropertySource<?> propertySource) { public void addFirstPropertySource(PropertySource<?> propertySource) {
List<PropertySource<?>> existing = new ArrayList<PropertySource<?>>(this.propertySources); List<PropertySource<?>> existing = new ArrayList<>(this.propertySources);
this.propertySources.clear(); this.propertySources.clear();
this.propertySources.add(propertySource); this.propertySources.add(propertySource);
this.propertySources.addAll(existing); this.propertySources.addAll(existing);

View File

@@ -28,7 +28,7 @@ public class MutablePropertySources implements PropertySources {
private final Log logger; private final Log logger;
private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>(); private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();
/** /**
* Create a new {@link MutablePropertySources} * Create a new {@link MutablePropertySources}

View File

@@ -31,7 +31,7 @@ public class SpringProfileDocumentMatcher implements YamlProcessor.DocumentMatch
} }
public void addActiveProfiles(String... profiles) { public void addActiveProfiles(String... profiles) {
LinkedHashSet<String> set = new LinkedHashSet<String>(Arrays.asList(this.activeProfiles)); LinkedHashSet<String> set = new LinkedHashSet<>(Arrays.asList(this.activeProfiles));
Collections.addAll(set, profiles); Collections.addAll(set, profiles);
this.activeProfiles = set.toArray(new String[set.size()]); this.activeProfiles = set.toArray(new String[set.size()]);
} }
@@ -67,14 +67,14 @@ public class SpringProfileDocumentMatcher implements YamlProcessor.DocumentMatch
private ProfilesMatcher getProfilesMatcher() { private ProfilesMatcher getProfilesMatcher() {
return (this.activeProfiles.length != 0 ? new ActiveProfilesMatcher( return (this.activeProfiles.length != 0 ? new ActiveProfilesMatcher(
new HashSet<String>(Arrays.asList(this.activeProfiles))) : new EmptyProfilesMatcher()); new HashSet<>(Arrays.asList(this.activeProfiles))) : new EmptyProfilesMatcher());
} }
private Set<String> extractProfiles(List<String> profiles, ProfileType type) { private Set<String> extractProfiles(List<String> profiles, ProfileType type) {
if (CollectionUtils.isEmpty(profiles)) { if (CollectionUtils.isEmpty(profiles)) {
return null; return null;
} }
Set<String> extractedProfiles = new HashSet<String>(); Set<String> extractedProfiles = new HashSet<>();
for (String candidate : profiles) { for (String candidate : profiles) {
ProfileType candidateType = ProfileType.POSITIVE; ProfileType candidateType = ProfileType.POSITIVE;
if (candidate.startsWith("!")) { if (candidate.startsWith("!")) {
@@ -167,7 +167,7 @@ public class SpringProfileDocumentMatcher implements YamlProcessor.DocumentMatch
*/ */
static class SpringProperties { static class SpringProperties {
private List<String> profiles = new ArrayList<String>(); private List<String> profiles = new ArrayList<>();
public List<String> getProfiles() { public List<String> getProfiles() {
return this.profiles; return this.profiles;

View File

@@ -130,8 +130,7 @@ public abstract class YamlProcessor {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Loading from YAML: " + resource); logger.debug("Loading from YAML: " + resource);
} }
Reader reader = new UnicodeReader(resource.getInputStream()); try (Reader reader = new UnicodeReader(resource.getInputStream())) {
try {
for (Object object : yaml.loadAll(reader)) { for (Object object : yaml.loadAll(reader)) {
if (object != null && process(asMap(object), callback)) { if (object != null && process(asMap(object), callback)) {
count++; count++;
@@ -142,10 +141,8 @@ public abstract class YamlProcessor {
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug( logger.debug(
"Loaded " + count + " document" + (count > 1 ? "s" : "") + " from YAML resource: " + resource); "Loaded " + count + " document" + (count > 1 ? "s" : "") + " from YAML resource: " + resource);
} }
} finally {
reader.close();
} }
} catch (IOException ex) { } catch (IOException ex) {
handleProcessError(resource, ex); handleProcessError(resource, ex);
@@ -166,7 +163,7 @@ public abstract class YamlProcessor {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Map<String, Object> asMap(Object object) { private Map<String, Object> asMap(Object object) {
// YAML can have numbers as keys // YAML can have numbers as keys
Map<String, Object> result = new LinkedHashMap<String, Object>(); Map<String, Object> result = new LinkedHashMap<>();
if (!(object instanceof Map)) { if (!(object instanceof Map)) {
// A document can be a text literal // A document can be a text literal
result.put("document", object); result.put("document", object);
@@ -249,7 +246,7 @@ public abstract class YamlProcessor {
* @since 4.1.3 * @since 4.1.3
*/ */
protected final Map<String, Object> getFlattenedMap(Map<String, Object> source) { protected final Map<String, Object> getFlattenedMap(Map<String, Object> source) {
Map<String, Object> result = new LinkedHashMap<String, Object>(); Map<String, Object> result = new LinkedHashMap<>();
buildFlattenedMap(result, source, null); buildFlattenedMap(result, source, null);
return result; return result;
} }

View File

@@ -3,7 +3,6 @@ package com.alibaba.otter.canal.client.adapter.config.common;
import java.io.IOException; import java.io.IOException;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@@ -72,14 +71,8 @@ public class YamlPropertySourceLoader implements PropertySourceLoader {
} }
public Map<String, Object> process() { public Map<String, Object> process() {
final Map<String, Object> result = new LinkedHashMap<String, Object>(); final Map<String, Object> result = new LinkedHashMap<>();
process(new MatchCallback() { process((properties, map) -> result.putAll(getFlattenedMap(map)));
@Override
public void process(Properties properties, Map<String, Object> map) {
result.putAll(getFlattenedMap(map));
}
});
return result; return result;
} }

View File

@@ -6,6 +6,7 @@ import java.io.InputStreamReader;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Arrays; import java.util.Arrays;
@@ -259,7 +260,7 @@ public class ExtensionLoader<T> {
} }
} }
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>(); Map<String, Class<?>> extensionClasses = new HashMap<>();
// 1. plugin folder,customized extension classLoader (jar_dir/plugin) // 1. plugin folder,customized extension classLoader (jar_dir/plugin)
String dir = File.separator + this.getJarDirectoryPath() + File.separator + "plugin"; String dir = File.separator + this.getJarDirectoryPath() + File.separator + "plugin";
@@ -317,10 +318,8 @@ public class ExtensionLoader<T> {
while (urls.hasMoreElements()) { while (urls.hasMoreElements()) {
URL url = urls.nextElement(); URL url = urls.nextElement();
try { try {
BufferedReader reader = null; try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
try { String line;
reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
String line = null;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
final int ci = line.indexOf('#'); final int ci = line.indexOf('#');
if (ci >= 0) line = line.substring(0, ci); if (ci >= 0) line = line.substring(0, ci);
@@ -340,10 +339,10 @@ public class ExtensionLoader<T> {
// classLoader); // classLoader);
if (!type.isAssignableFrom(clazz)) { if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException( throw new IllegalStateException(
"Error when load extension class(interface: " + type "Error when load extension class(interface: " + type
+ ", class line: " + clazz.getName() + ", class line: " + clazz.getName()
+ "), class " + clazz.getName() + "), class " + clazz.getName()
+ "is not subtype of interface."); + "is not subtype of interface.");
} else { } else {
try { try {
clazz.getConstructor(type); clazz.getConstructor(type);
@@ -361,10 +360,10 @@ public class ExtensionLoader<T> {
} else if (c != clazz) { } else if (c != clazz) {
cachedNames.remove(clazz); cachedNames.remove(clazz);
throw new IllegalStateException( throw new IllegalStateException(
"Duplicate extension " + type.getName() + " name " "Duplicate extension " + type.getName() + " name "
+ n + " on " + n + " on "
+ c.getName() + " and " + c.getName() + " and "
+ clazz.getName()); + clazz.getName());
} }
} }
} }
@@ -373,19 +372,15 @@ public class ExtensionLoader<T> {
} }
} catch (Throwable t) { } catch (Throwable t) {
IllegalStateException e = new IllegalStateException( IllegalStateException e = new IllegalStateException(
"Failed to load extension class(interface: " + type + ", class line: " "Failed to load extension class(interface: " + type + ", class line: "
+ line + ") in " + url + line + ") in " + url
+ ", cause: " + ", cause: "
+ t.getMessage(), + t.getMessage(),
t); t);
exceptions.put(line, e); exceptions.put(line, e);
} }
} }
} // end of while read lines } // end of while read lines
} finally {
if (reader != null) {
reader.close();
}
} }
} catch (Throwable t) { } catch (Throwable t) {
logger.error("Exception when load extension class(interface: " + type + ", class file: " + url logger.error("Exception when load extension class(interface: " + type + ", class file: " + url

View File

@@ -4,7 +4,6 @@ import java.util.*;
import com.alibaba.otter.canal.connector.core.consumer.CommonMessage; import com.alibaba.otter.canal.connector.core.consumer.CommonMessage;
import com.alibaba.otter.canal.protocol.CanalEntry; import com.alibaba.otter.canal.protocol.CanalEntry;
import com.alibaba.otter.canal.protocol.FlatMessage;
import com.alibaba.otter.canal.protocol.Message; import com.alibaba.otter.canal.protocol.Message;
/** /**
@@ -20,7 +19,7 @@ public class MessageUtil {
return null; return null;
} }
List<CanalEntry.Entry> entries = message.getEntries(); List<CanalEntry.Entry> entries = message.getEntries();
List<Dml> dmls = new ArrayList<Dml>(entries.size()); List<Dml> dmls = new ArrayList<>(entries.size());
for (CanalEntry.Entry entry : entries) { for (CanalEntry.Entry entry : entries) {
if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN
|| entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) { || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {
@@ -136,7 +135,7 @@ public class MessageUtil {
if (commonMessages == null) { if (commonMessages == null) {
return new ArrayList<>(); return new ArrayList<>();
} }
List<Dml> dmls = new ArrayList<Dml>(commonMessages.size()); List<Dml> dmls = new ArrayList<>(commonMessages.size());
for (CommonMessage commonMessage : commonMessages) { for (CommonMessage commonMessage : commonMessages) {
Dml dml = flatMessage2Dml(destination, groupId, commonMessage); Dml dml = flatMessage2Dml(destination, groupId, commonMessage);
if (dml != null) { if (dml != null) {

View File

@@ -7,7 +7,8 @@ import java.util.Enumeration;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
public class URLClassExtensionLoader extends URLClassLoader { public class URLClassExtensionLoader extends URLClassLoader {
public URLClassExtensionLoader(URL[] urls) {
public URLClassExtensionLoader(URL[] urls){
super(urls); super(urls);
} }
@@ -18,9 +19,9 @@ public class URLClassExtensionLoader extends URLClassLoader {
return c; return c;
} }
if (name.startsWith("java.") || name.startsWith("org.slf4j.") if (name.startsWith("java.") || name.startsWith("org.slf4j.") || name.startsWith("org.apache.logging")
|| name.startsWith("org.apache.logging") || name.startsWith("org.apache.zookeeper.") || name.startsWith("org.I0Itec.zkclient.")
|| name.startsWith("org.apache.commons.logging.")) { || name.startsWith("org.apache.commons.logging.")) {
// || name.startsWith("org.apache.hadoop.")) // || name.startsWith("org.apache.hadoop."))
// { // {
c = super.loadClass(name); c = super.loadClass(name);

View File

@@ -1,24 +1,13 @@
package com.alibaba.otter.canal.client.adapter.support; package com.alibaba.otter.canal.client.adapter.support;
import static org.mockito.AdditionalMatchers.or;
import static org.mockito.Matchers.isA;
import static org.mockito.Matchers.isNull;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import com.alibaba.otter.canal.client.adapter.support.JdbcTypeUtil;
import com.alibaba.otter.canal.client.adapter.support.Util;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.junit.rules.Timeout; import org.junit.rules.Timeout;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import java.lang.reflect.Array;
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
public class JdbcTypeUtilTest { public class JdbcTypeUtilTest {

View File

@@ -3,9 +3,7 @@ package com.alibaba.otter.canal.client.adapter.support;
import static org.mockito.AdditionalMatchers.or; import static org.mockito.AdditionalMatchers.or;
import static org.mockito.Matchers.isA; import static org.mockito.Matchers.isA;
import static org.mockito.Matchers.isNull; import static org.mockito.Matchers.isNull;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import com.alibaba.otter.canal.client.adapter.support.Util;
import com.diffblue.deeptestutils.mock.DTUMemberMatcher; import com.diffblue.deeptestutils.mock.DTUMemberMatcher;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.junit.Assert; import org.junit.Assert;

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -2,7 +2,10 @@ package com.alibaba.otter.canal.client.adapter.es6x.support;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@@ -78,14 +81,7 @@ public class ESConnection {
Integer.parseInt(host.substring(i + 1)))); Integer.parseInt(host.substring(i + 1))));
} }
} else { } else {
HttpHost[] httpHosts = new HttpHost[hosts.length]; HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);
for (int i = 0; i < hosts.length; i++) {
String host = hosts[i];
int j = host.indexOf(":");
HttpHost httpHost = new HttpHost(InetAddress.getByName(host.substring(0, j)),
Integer.parseInt(host.substring(j + 1)));
httpHosts[i] = httpHost;
}
RestClientBuilder restClientBuilder = RestClient.builder(httpHosts); RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);
String nameAndPwd = properties.get("security.auth"); String nameAndPwd = properties.get("security.auth");
if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(":")) { if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(":")) {
@@ -507,4 +503,17 @@ public class ESConnection {
public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) { public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) {
this.restHighLevelClient = restHighLevelClient; this.restHighLevelClient = restHighLevelClient;
} }
private HttpHost createHttpHost(String uriStr) {
URI uri = URI.create(uriStr);
if (!org.springframework.util.StringUtils.hasLength(uri.getUserInfo())) {
return HttpHost.create(uri.toString());
}
try {
return HttpHost.create(new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(),
uri.getQuery(), uri.getFragment()).toString());
} catch (URISyntaxException ex) {
throw new IllegalStateException(ex);
}
}
} }

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -2,7 +2,10 @@ package com.alibaba.otter.canal.client.adapter.es7x.support;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@@ -77,14 +80,7 @@ public class ESConnection {
Integer.parseInt(host.substring(i + 1)))); Integer.parseInt(host.substring(i + 1))));
} }
} else { } else {
HttpHost[] httpHosts = new HttpHost[hosts.length]; HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);
for (int i = 0; i < hosts.length; i++) {
String host = hosts[i];
int j = host.indexOf(":");
HttpHost httpHost = new HttpHost(InetAddress.getByName(host.substring(0, j)),
Integer.parseInt(host.substring(j + 1)));
httpHosts[i] = httpHost;
}
RestClientBuilder restClientBuilder = RestClient.builder(httpHosts); RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);
String nameAndPwd = properties.get("security.auth"); String nameAndPwd = properties.get("security.auth");
if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(":")) { if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(":")) {
@@ -501,4 +497,17 @@ public class ESConnection {
public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) { public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) {
this.restHighLevelClient = restHighLevelClient; this.restHighLevelClient = restHighLevelClient;
} }
private HttpHost createHttpHost(String uriStr) {
URI uri = URI.create(uriStr);
if (!org.springframework.util.StringUtils.hasLength(uri.getUserInfo())) {
return HttpHost.create(uri.toString());
}
try {
return HttpHost.create(new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(),
uri.getQuery(), uri.getFragment()).toString());
} catch (URISyntaxException ex) {
throw new IllegalStateException(ex);
}
}
} }

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -22,8 +20,8 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.alibaba.fastsql</groupId> <groupId>com.alibaba</groupId>
<artifactId>fastsql</artifactId> <artifactId>druid</artifactId>
</dependency> </dependency>
<dependency> <dependency>

View File

@@ -1,31 +1,31 @@
package com.alibaba.otter.canal.client.adapter.es.core.config; package com.alibaba.otter.canal.client.adapter.es.core.config;
import static com.alibaba.fastsql.sql.ast.expr.SQLBinaryOperator.BooleanAnd; import static com.alibaba.druid.sql.ast.expr.SQLBinaryOperator.BooleanAnd;
import static com.alibaba.fastsql.sql.ast.expr.SQLBinaryOperator.Equality; import static com.alibaba.druid.sql.ast.expr.SQLBinaryOperator.Equality;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.alibaba.fastsql.sql.SQLUtils; import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.fastsql.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.fastsql.sql.ast.expr.SQLBinaryOpExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.fastsql.sql.ast.expr.SQLCaseExpr; import com.alibaba.druid.sql.ast.expr.SQLCaseExpr;
import com.alibaba.fastsql.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.fastsql.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.fastsql.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.fastsql.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.fastsql.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.fastsql.sql.ast.statement.SQLJoinTableSource; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.fastsql.sql.ast.statement.SQLSelectGroupByClause; import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause;
import com.alibaba.fastsql.sql.ast.statement.SQLSelectItem; import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.fastsql.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.fastsql.sql.ast.statement.SQLSubqueryTableSource; import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.alibaba.fastsql.sql.ast.statement.SQLTableSource; import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.fastsql.sql.dialect.mysql.parser.MySqlStatementParser; import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.fastsql.sql.parser.ParserException; import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.fastsql.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.ColumnItem; import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.ColumnItem;
import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem; import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;
import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.RelationFieldsPair; import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.RelationFieldsPair;
@@ -230,8 +230,7 @@ public class SqlParser {
} }
FieldItem rightFieldItem = new FieldItem(); FieldItem rightFieldItem = new FieldItem();
visitColumn(sqlBinaryOpExpr.getRight(), rightFieldItem); visitColumn(sqlBinaryOpExpr.getRight(), rightFieldItem);
if (rightFieldItem.getColumnItems().size() != 1 || rightFieldItem.isMethod() if (rightFieldItem.getColumnItems().size() != 1 || rightFieldItem.isMethod() || rightFieldItem.isBinaryOp()) {
|| rightFieldItem.isBinaryOp()) {
throw new UnsupportedOperationException("Unsupported for complex of on-condition"); throw new UnsupportedOperationException("Unsupported for complex of on-condition");
} }
tableItem.getRelationFields().add(new RelationFieldsPair(leftFieldItem, rightFieldItem)); tableItem.getRelationFields().add(new RelationFieldsPair(leftFieldItem, rightFieldItem));

View File

@@ -13,7 +13,7 @@ import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig; import com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;
import com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping; import com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;
import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem; import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem;

View File

@@ -63,172 +63,187 @@ public class ESSyncUtil {
return val; return val;
} }
Object res = null; Object res = null;
if ("integer".equals(esType)) { switch (esType) {
if (val instanceof Number) { case "integer":
res = ((Number) val).intValue(); if (val instanceof Number) {
} else { res = ((Number) val).intValue();
res = Integer.parseInt(val.toString());
}
} else if ("long".equals(esType)) {
if (val instanceof Number) {
res = ((Number) val).longValue();
} else {
res = Long.parseLong(val.toString());
}
} else if ("short".equals(esType)) {
if (val instanceof Number) {
res = ((Number) val).shortValue();
} else {
res = Short.parseShort(val.toString());
}
} else if ("byte".equals(esType)) {
if (val instanceof Number) {
res = ((Number) val).byteValue();
} else {
res = Byte.parseByte(val.toString());
}
} else if ("double".equals(esType)) {
if (val instanceof Number) {
res = ((Number) val).doubleValue();
} else {
res = Double.parseDouble(val.toString());
}
} else if ("float".equals(esType) || "half_float".equals(esType) || "scaled_float".equals(esType)) {
if (val instanceof Number) {
res = ((Number) val).floatValue();
} else {
res = Float.parseFloat(val.toString());
}
} else if ("boolean".equals(esType)) {
if (val instanceof Boolean) {
res = val;
} else if (val instanceof Number) {
int v = ((Number) val).intValue();
res = v != 0;
} else {
res = Boolean.parseBoolean(val.toString());
}
} else if ("date".equals(esType)) {
if (val instanceof java.sql.Time) {
DateTime dateTime = new DateTime(((java.sql.Time) val).getTime());
if (dateTime.getMillisOfSecond() != 0) {
res = dateTime.toString("HH:mm:ss.SSS");
} else { } else {
res = dateTime.toString("HH:mm:ss"); res = Integer.parseInt(val.toString());
} }
} else if (val instanceof java.sql.Timestamp) { break;
DateTime dateTime = new DateTime(((java.sql.Timestamp) val).getTime()); case "long":
if (dateTime.getMillisOfSecond() != 0) { if (val instanceof Number) {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone); res = ((Number) val).longValue();
} else { } else {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss" + Util.timeZone); res = Long.parseLong(val.toString());
} }
} else if (val instanceof java.sql.Date || val instanceof Date) { break;
DateTime dateTime; case "short":
if (val instanceof java.sql.Date) { if (val instanceof Number) {
dateTime = new DateTime(((java.sql.Date) val).getTime()); res = ((Number) val).shortValue();
} else { } else {
dateTime = new DateTime(((Date) val).getTime()); res = Short.parseShort(val.toString());
} }
if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0 break;
&& dateTime.getMillisOfSecond() == 0) { case "byte":
res = dateTime.toString("yyyy-MM-dd"); if (val instanceof Number) {
res = ((Number) val).byteValue();
} else { } else {
res = Byte.parseByte(val.toString());
}
break;
case "double":
if (val instanceof Number) {
res = ((Number) val).doubleValue();
} else {
res = Double.parseDouble(val.toString());
}
break;
case "float":
case "half_float":
case "scaled_float":
if (val instanceof Number) {
res = ((Number) val).floatValue();
} else {
res = Float.parseFloat(val.toString());
}
break;
case "boolean":
if (val instanceof Boolean) {
res = val;
} else if (val instanceof Number) {
int v = ((Number) val).intValue();
res = v != 0;
} else {
res = Boolean.parseBoolean(val.toString());
}
break;
case "date":
if (val instanceof java.sql.Time) {
DateTime dateTime = new DateTime(((java.sql.Time) val).getTime());
if (dateTime.getMillisOfSecond() != 0) {
res = dateTime.toString("HH:mm:ss.SSS");
} else {
res = dateTime.toString("HH:mm:ss");
}
} else if (val instanceof java.sql.Timestamp) {
DateTime dateTime = new DateTime(((java.sql.Timestamp) val).getTime());
if (dateTime.getMillisOfSecond() != 0) { if (dateTime.getMillisOfSecond() != 0) {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone); res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone);
} else { } else {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss" + Util.timeZone); res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss" + Util.timeZone);
} }
} } else if (val instanceof java.sql.Date || val instanceof Date) {
} else if (val instanceof Long) { DateTime dateTime;
DateTime dateTime = new DateTime(((Long) val).longValue()); if (val instanceof java.sql.Date) {
if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0 dateTime = new DateTime(((java.sql.Date) val).getTime());
&& dateTime.getMillisOfSecond() == 0) { } else {
res = dateTime.toString("yyyy-MM-dd"); dateTime = new DateTime(((Date) val).getTime());
} else if (dateTime.getMillisOfSecond() != 0) { }
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone); if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0
} else { && dateTime.getMillisOfSecond() == 0) {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss" + Util.timeZone); res = dateTime.toString("yyyy-MM-dd");
} } else {
} else if (val instanceof String) {
String v = ((String) val).trim();
if (v.length() > 18 && v.charAt(4) == '-' && v.charAt(7) == '-' && v.charAt(10) == ' '
&& v.charAt(13) == ':' && v.charAt(16) == ':') {
String dt = v.substring(0, 10) + "T" + v.substring(11);
Date date = Util.parseDate(dt);
if (date != null) {
DateTime dateTime = new DateTime(date);
if (dateTime.getMillisOfSecond() != 0) { if (dateTime.getMillisOfSecond() != 0) {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone); res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone);
} else { } else {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss" + Util.timeZone); res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss" + Util.timeZone);
} }
} }
} else if (v.length() == 10 && v.charAt(4) == '-' && v.charAt(7) == '-') { } else if (val instanceof Long) {
Date date = Util.parseDate(v); DateTime dateTime = new DateTime(((Long) val).longValue());
if (date != null) { if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0
DateTime dateTime = new DateTime(date); && dateTime.getMillisOfSecond() == 0) {
res = dateTime.toString("yyyy-MM-dd"); res = dateTime.toString("yyyy-MM-dd");
} else if (dateTime.getMillisOfSecond() != 0) {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone);
} else {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss" + Util.timeZone);
}
} else if (val instanceof String) {
String v = ((String) val).trim();
if (v.length() > 18 && v.charAt(4) == '-' && v.charAt(7) == '-' && v.charAt(10) == ' '
&& v.charAt(13) == ':' && v.charAt(16) == ':') {
String dt = v.substring(0, 10) + "T" + v.substring(11);
Date date = Util.parseDate(dt);
if (date != null) {
DateTime dateTime = new DateTime(date);
if (dateTime.getMillisOfSecond() != 0) {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone);
} else {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss" + Util.timeZone);
}
}
} else if (v.length() == 10 && v.charAt(4) == '-' && v.charAt(7) == '-') {
Date date = Util.parseDate(v);
if (date != null) {
DateTime dateTime = new DateTime(date);
res = dateTime.toString("yyyy-MM-dd");
}
} }
} }
} break;
} else if ("binary".equals(esType)) { case "binary":
if (val instanceof byte[]) { if (val instanceof byte[]) {
Base64 base64 = new Base64(); Base64 base64 = new Base64();
res = base64.encodeAsString((byte[]) val); res = base64.encodeAsString((byte[]) val);
} else if (val instanceof Blob) { } else if (val instanceof Blob) {
byte[] b = blobToBytes((Blob) val); byte[] b = blobToBytes((Blob) val);
Base64 base64 = new Base64(); Base64 base64 = new Base64();
res = base64.encodeAsString(b); res = base64.encodeAsString(b);
} else if (val instanceof String) { } else if (val instanceof String) {
// 对应canal中的单字节编码 // 对应canal中的单字节编码
byte[] b = ((String) val).getBytes(StandardCharsets.ISO_8859_1); byte[] b = ((String) val).getBytes(StandardCharsets.ISO_8859_1);
Base64 base64 = new Base64(); Base64 base64 = new Base64();
res = base64.encodeAsString(b); res = base64.encodeAsString(b);
}
} else if ("geo_point".equals(esType)) {
if (!(val instanceof String)) {
logger.error("es type is geo_point, but source type is not String");
return val;
}
if (!((String) val).contains(",")) {
logger.error("es type is geo_point, source value not contains ',' separator");
return val;
}
String[] point = ((String) val).split(",");
Map<String, Double> location = new HashMap<>();
location.put("lat", Double.valueOf(point[0].trim()));
location.put("lon", Double.valueOf(point[1].trim()));
return location;
} else if ("array".equals(esType)) {
if ("".equals(val.toString().trim())) {
res = new ArrayList<>();
} else {
String value = val.toString();
String separator = ",";
if (!value.contains(",")) {
if (value.contains(";")) {
separator = ";";
} else if (value.contains("|")) {
separator = "\\|";
} else if (value.contains("-")) {
separator = "-";
}
} }
String[] values = value.split(separator); break;
return Arrays.asList(values); case "geo_point":
} if (!(val instanceof String)) {
} else if ("object".equals(esType)) { logger.error("es type is geo_point, but source type is not String");
if ("".equals(val.toString().trim())) { return val;
res = new HashMap<>(); }
} else {
res = JSON.parseObject(val.toString(), Map.class); if (!((String) val).contains(",")) {
} logger.error("es type is geo_point, source value not contains ',' separator");
} else { return val;
// 其他类全以字符串处理 }
res = val.toString();
String[] point = ((String) val).split(",");
Map<String, Double> location = new HashMap<>();
location.put("lat", Double.valueOf(point[0].trim()));
location.put("lon", Double.valueOf(point[1].trim()));
return location;
case "array":
if ("".equals(val.toString().trim())) {
res = new ArrayList<>();
} else {
String value = val.toString();
String separator = ",";
if (!value.contains(",")) {
if (value.contains(";")) {
separator = ";";
} else if (value.contains("|")) {
separator = "\\|";
} else if (value.contains("-")) {
separator = "-";
}
}
String[] values = value.split(separator);
return Arrays.asList(values);
}
break;
case "object":
if ("".equals(val.toString().trim())) {
res = new HashMap<>();
} else {
res = JSON.parseObject(val.toString(), Map.class);
}
break;
default:
// 其他类全以字符串处理
res = val.toString();
break;
} }
return res; return res;

View File

@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -20,7 +20,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.hbase</groupId> <groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId> <artifactId>hbase-shaded-client</artifactId>
<version>1.1.2</version> <version>1.1.2</version>
<exclusions> <exclusions>
<exclusion> <exclusion>

View File

@@ -1,9 +1,10 @@
package com.alibaba.otter.canal.client.adapter.hbase.monitor; package com.alibaba.otter.canal.client.adapter.hbase.monitor;
import java.io.File; import com.alibaba.otter.canal.client.adapter.config.YmlConfigBinder;
import java.util.HashMap; import com.alibaba.otter.canal.client.adapter.hbase.HbaseAdapter;
import java.util.Map; import com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig;
import java.util.Properties; import com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;
import com.alibaba.otter.canal.client.adapter.support.Util;
import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor; import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
@@ -13,11 +14,10 @@ import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.alibaba.otter.canal.client.adapter.config.YmlConfigBinder; import java.io.File;
import com.alibaba.otter.canal.client.adapter.hbase.HbaseAdapter; import java.util.HashMap;
import com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig; import java.util.Map;
import com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader; import java.util.Properties;
import com.alibaba.otter.canal.client.adapter.support.Util;
public class HbaseConfigMonitor { public class HbaseConfigMonitor {
@@ -125,8 +125,8 @@ public class HbaseConfigMonitor {
private void addConfigToCache(File file, MappingConfig config) { private void addConfigToCache(File file, MappingConfig config) {
hbaseAdapter.getHbaseMapping().put(file.getName(), config); hbaseAdapter.getHbaseMapping().put(file.getName(), config);
Map<String, MappingConfig> configMap = hbaseAdapter.getMappingConfigCache() Map<String, MappingConfig> configMap = hbaseAdapter.getMappingConfigCache()
.computeIfAbsent(StringUtils.trimToEmpty(config.getDestination()) + "." .computeIfAbsent(StringUtils.trimToEmpty(config.getDestination()) + "_"
+ config.getHbaseMapping().getDatabase() + "." + config.getHbaseMapping().getTable(), + config.getHbaseMapping().getDatabase() + "-" + config.getHbaseMapping().getTable(),
k1 -> new HashMap<>()); k1 -> new HashMap<>());
configMap.put(file.getName(), config); configMap.put(file.getName(), config);
} }

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -73,7 +71,7 @@
<tasks> <tasks>
<copy todir="${project.basedir}/../launcher/target/classes/kudu" overwrite="true"> <copy todir="${project.basedir}/../launcher/target/classes/kudu" overwrite="true">
<fileset dir="${project.basedir}/target/classes/kudu" erroronmissingdir="true"> <fileset dir="${project.basedir}/target/classes/kudu" erroronmissingdir="true">
<include name="*.yml"/> <include name="*.yml" />
</fileset> </fileset>
</copy> </copy>
</tasks> </tasks>

View File

@@ -88,45 +88,40 @@ public class KuduEtlService extends AbstractEtlService {
Map<String, Object> data = new HashMap<>(); Map<String, Object> data = new HashMap<>();
for (Map.Entry<String, String> entry : columnsMap.entrySet()) { for (Map.Entry<String, String> entry : columnsMap.entrySet()) {
String mysqlColumnName = entry.getKey();// mysql字段名 String mysqlColumnName = entry.getKey();// mysql字段名
String kuduColumnName = entry.getValue();// kudu字段名 String kuduColumnName = entry.getValue();// kudu字段名
if (kuduColumnName == null) { if (kuduColumnName == null) {
kuduColumnName = mysqlColumnName; kuduColumnName = mysqlColumnName;
} }
Object value = rs.getObject(kuduColumnName); Object value = rs.getObject(kuduColumnName);
if (value != null) { if (value != null) {
data.put(kuduColumnName, value); data.put(kuduColumnName, value);
} else { } else {
data.put(kuduColumnName, null); data.put(kuduColumnName, null);
} }
} }
dataList.add(data); dataList.add(data);
idx++; idx++;
impCount.incrementAndGet(); impCount.incrementAndGet();
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("successful import count:" + impCount.get()); logger.debug("successful import count:" + impCount.get());
} }
if (idx % kuduMapping.getCommitBatch() == 0) { if (idx % kuduMapping.getCommitBatch() == 0) {
kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList); kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);
dataList.clear(); dataList.clear();
} }
} }
if (!dataList.isEmpty()) { if (!dataList.isEmpty()) {
kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList); kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);
} }
return true; return true;
} catch (SQLException e) { } catch (SQLException | KuduException e) {
e.printStackTrace(); e.printStackTrace();
logger.error(kuduMapping.getTargetTable() + " etl failed! ==>" + e.getMessage(), e); logger.error(kuduMapping.getTargetTable() + " etl failed! ==>" + e.getMessage(), e);
errMsg.add(kuduMapping.getTargetTable() + " etl failed! ==>" + e.getMessage()); errMsg.add(kuduMapping.getTargetTable() + " etl failed! ==>" + e.getMessage());
return false; return false;
} catch (KuduException e) { }
e.printStackTrace(); });
logger.error(kuduMapping.getTargetTable() + " etl failed! ==>" + e.getMessage(), e);
errMsg.add(kuduMapping.getTargetTable() + " etl failed! ==>" + e.getMessage());
return false;
}
} );
return true; return true;
} catch (Exception e) { } catch (Exception e) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);

View File

@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -69,6 +69,12 @@
<artifactId>mssql-jdbc</artifactId> <artifactId>mssql-jdbc</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-shaded-client</artifactId>
<scope>runtime</scope>
</dependency>
<!-- outer adapter jar with dependencies--> <!-- outer adapter jar with dependencies-->
<dependency> <dependency>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>

View File

@@ -1,5 +1,13 @@
#!/bin/bash #!/bin/bash
sh stop.sh case $(uname) in
Linux)
bin_abs_path=$(readlink -f $(dirname $0))
;;
*)
bin_abs_path=$(cd $(dirname $0) ||exit ; pwd)
;;
esac
sh startup.sh sh "$bin_abs_path"/stop.sh
sh "$bin_abs_path"/startup.sh

View File

@@ -211,6 +211,7 @@ public class AdapterProcessor {
canalDestination, canalDestination,
System.currentTimeMillis() - begin); System.currentTimeMillis() - begin);
} }
break;
} catch (Exception e) { } catch (Exception e) {
if (i != retry - 1) { if (i != retry - 1) {
canalMsgConsumer.rollback(); // 处理失败, 回滚数据 canalMsgConsumer.rollback(); // 处理失败, 回滚数据

View File

@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -4,12 +4,12 @@
<parent> <parent>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<artifactId>canal</artifactId> <artifactId>canal</artifactId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>canal client adapter module for otter ${project.version}</name> <name>canal client adapter module for otter ${project.version}</name>
@@ -192,7 +192,7 @@
<dependency> <dependency>
<groupId>org.apache.hbase</groupId> <groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId> <artifactId>hbase-shaded-client</artifactId>
<version>1.1.2</version> <version>1.1.2</version>
<exclusions> <exclusions>
<exclusion> <exclusion>

View File

@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>canal.client-adapter</artifactId> <artifactId>canal.client-adapter</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -1,27 +1,22 @@
package com.alibaba.otter.canal.client.adapter.rdb.support; package com.alibaba.otter.canal.client.adapter.rdb.support;
import com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig;
import com.alibaba.otter.canal.client.adapter.support.Util;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.sql.Blob; import java.sql.*;
import java.sql.Clob;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang.StringUtils;
import com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig;
import com.alibaba.otter.canal.client.adapter.support.Util;
public class SyncUtil { public class SyncUtil {
private static final Logger logger = LoggerFactory.getLogger(SyncUtil.class);
public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Map<String, Object> data) { public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Map<String, Object> data) {
return getColumnsMap(dbMapping, data.keySet()); return getColumnsMap(dbMapping, data.keySet());
@@ -93,15 +88,7 @@ public class SyncUtil {
} }
break; break;
case Types.TINYINT: case Types.TINYINT:
if (value instanceof Number) { // 向上提升一级,处理unsigned情况
pstmt.setByte(i, ((Number) value).byteValue());
} else if (value instanceof String) {
pstmt.setByte(i, Byte.parseByte((String) value));
} else {
pstmt.setNull(i, type);
}
break;
case Types.SMALLINT:
if (value instanceof Number) { if (value instanceof Number) {
pstmt.setShort(i, ((Number) value).shortValue()); pstmt.setShort(i, ((Number) value).shortValue());
} else if (value instanceof String) { } else if (value instanceof String) {
@@ -110,7 +97,7 @@ public class SyncUtil {
pstmt.setNull(i, type); pstmt.setNull(i, type);
} }
break; break;
case Types.INTEGER: case Types.SMALLINT:
if (value instanceof Number) { if (value instanceof Number) {
pstmt.setInt(i, ((Number) value).intValue()); pstmt.setInt(i, ((Number) value).intValue());
} else if (value instanceof String) { } else if (value instanceof String) {
@@ -119,7 +106,7 @@ public class SyncUtil {
pstmt.setNull(i, type); pstmt.setNull(i, type);
} }
break; break;
case Types.BIGINT: case Types.INTEGER:
if (value instanceof Number) { if (value instanceof Number) {
pstmt.setLong(i, ((Number) value).longValue()); pstmt.setLong(i, ((Number) value).longValue());
} else if (value instanceof String) { } else if (value instanceof String) {
@@ -128,6 +115,15 @@ public class SyncUtil {
pstmt.setNull(i, type); pstmt.setNull(i, type);
} }
break; break;
case Types.BIGINT:
if (value instanceof Number) {
pstmt.setBigDecimal(i, new BigDecimal(value.toString()));
} else if (value instanceof String) {
pstmt.setBigDecimal(i, new BigDecimal(value.toString()));
} else {
pstmt.setNull(i, type);
}
break;
case Types.DECIMAL: case Types.DECIMAL:
case Types.NUMERIC: case Types.NUMERIC:
if (value instanceof BigDecimal) { if (value instanceof BigDecimal) {
@@ -262,9 +258,9 @@ public class SyncUtil {
public static String getDbTableName(MappingConfig.DbMapping dbMapping) { public static String getDbTableName(MappingConfig.DbMapping dbMapping) {
String result = ""; String result = "";
if (StringUtils.isNotEmpty(dbMapping.getTargetDb())) { if (StringUtils.isNotEmpty(dbMapping.getTargetDb())) {
result += dbMapping.getTargetDb() + "."; result += ("`" + dbMapping.getTargetDb() + "`.");
} }
result += dbMapping.getTargetTable(); result += ("`" + dbMapping.getTargetTable() + "`");
return result; return result;
} }
} }

View File

@@ -1,14 +1,14 @@
//wpackage com.alibaba.otter.canal.client.adapter.rdb.test; //wpackage com.alibaba.otter.canal.client.adapter.rdb.test;
// //
//import com.alibaba.fastsql.sql.ast.SQLName; //import com.alibaba.druid.sql.ast.SQLName;
//import com.alibaba.fastsql.sql.ast.SQLStatement; //import com.alibaba.druid.sql.ast.SQLStatement;
//import com.alibaba.fastsql.sql.ast.statement.SQLCreateTableStatement; //import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
//import com.alibaba.fastsql.sql.ast.statement.SQLExprTableSource; //import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
//import com.alibaba.fastsql.sql.dialect.mysql.parser.MySqlCreateTableParser; //import com.alibaba.druid.sql.dialect.mysql.parser.MySqlCreateTableParser;
//import com.alibaba.fastsql.sql.dialect.mysql.parser.MySqlStatementParser; //import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
//import com.alibaba.fastsql.sql.dialect.mysql.visitor.MySqlOutputVisitor; //import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
//import com.alibaba.fastsql.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; //import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
//import com.alibaba.fastsql.sql.parser.SQLStatementParser; //import com.alibaba.druid.sql.parser.SQLStatementParser;
// //
//import java.io.StringWriter; //import java.io.StringWriter;
// //

View File

@@ -1,9 +1,9 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" "> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" ">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<artifactId>canal</artifactId> <artifactId>canal</artifactId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>

View File

@@ -28,19 +28,14 @@ public class ClusterNodeAccessStrategy implements CanalNodeAccessStrategy {
private IZkChildListener childListener; // 监听所有的服务器列表 private IZkChildListener childListener; // 监听所有的服务器列表
private IZkDataListener dataListener; // 监听当前的工作节点 private IZkDataListener dataListener; // 监听当前的工作节点
private ZkClientx zkClient; private ZkClientx zkClient;
private volatile List<InetSocketAddress> currentAddress = new ArrayList<InetSocketAddress>(); private volatile List<InetSocketAddress> currentAddress = new ArrayList<>();
private volatile InetSocketAddress runningAddress = null; private volatile InetSocketAddress runningAddress = null;
public ClusterNodeAccessStrategy(String destination, ZkClientx zkClient){ public ClusterNodeAccessStrategy(String destination, ZkClientx zkClient){
this.destination = destination; this.destination = destination;
this.zkClient = zkClient; this.zkClient = zkClient;
childListener = new IZkChildListener() { // handleChildChange
childListener = (parentPath, currentChilds) -> initClusters(currentChilds);
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
initClusters(currentChilds);
}
};
dataListener = new IZkDataListener() { dataListener = new IZkDataListener() {
@@ -80,9 +75,9 @@ public class ClusterNodeAccessStrategy implements CanalNodeAccessStrategy {
private void initClusters(List<String> currentChilds) { private void initClusters(List<String> currentChilds) {
if (currentChilds == null || currentChilds.isEmpty()) { if (currentChilds == null || currentChilds.isEmpty()) {
currentAddress = new ArrayList<InetSocketAddress>(); currentAddress = new ArrayList<>();
} else { } else {
List<InetSocketAddress> addresses = new ArrayList<InetSocketAddress>(); List<InetSocketAddress> addresses = new ArrayList<>();
for (String address : currentChilds) { for (String address : currentChilds) {
String[] strs = StringUtils.split(address, ":"); String[] strs = StringUtils.split(address, ":");
if (strs != null && strs.length == 2) { if (strs != null && strs.length == 2) {

View File

@@ -64,7 +64,7 @@ public class SimpleCanalConnector implements CanalConnector {
private SocketChannel channel; private SocketChannel channel;
private ReadableByteChannel readableChannel; private ReadableByteChannel readableChannel;
private WritableByteChannel writableChannel; private WritableByteChannel writableChannel;
private List<Compression> supportedCompressions = new ArrayList<Compression>(); private List<Compression> supportedCompressions = new ArrayList<>();
private ClientIdentity clientIdentity; private ClientIdentity clientIdentity;
private ClientRunningMonitor runningMonitor; // 运行控制 private ClientRunningMonitor runningMonitor; // 运行控制
private ZkClientx zkClientx; private ZkClientx zkClientx;

View File

@@ -14,7 +14,7 @@ import com.alibaba.otter.canal.client.CanalNodeAccessStrategy;
*/ */
public class SimpleNodeAccessStrategy implements CanalNodeAccessStrategy { public class SimpleNodeAccessStrategy implements CanalNodeAccessStrategy {
private List<SocketAddress> nodes = new ArrayList<SocketAddress>(); private List<SocketAddress> nodes = new ArrayList<>();
private int index = 0; private int index = 0;
public SimpleNodeAccessStrategy(List<? extends SocketAddress> nodes){ public SimpleNodeAccessStrategy(List<? extends SocketAddress> nodes){

View File

@@ -72,12 +72,7 @@ public class ClientRunningMonitor extends AbstractCanalLifeCycle {
initRunning(); initRunning();
} else { } else {
// 否则就是等待delayTime,避免因网络瞬端或者zk异常,导致出现频繁的切换操作 // 否则就是等待delayTime,避免因网络瞬端或者zk异常,导致出现频繁的切换操作
delayExector.schedule(new Runnable() { delayExector.schedule(() -> initRunning(), delayTime, TimeUnit.SECONDS);
public void run() {
initRunning();
}
}, delayTime, TimeUnit.SECONDS);
} }
} }

View File

@@ -80,11 +80,11 @@ public class KafkaCanalConnector implements CanalMQConnector {
connected = true; connected = true;
if (kafkaConsumer == null && !flatMessage) { if (kafkaConsumer == null && !flatMessage) {
kafkaConsumer = new KafkaConsumer<String, Message>(properties); kafkaConsumer = new KafkaConsumer<>(properties);
} }
if (kafkaConsumer2 == null && flatMessage) { if (kafkaConsumer2 == null && flatMessage) {
kafkaConsumer2 = new KafkaConsumer<String, String>(properties); kafkaConsumer2 = new KafkaConsumer<>(properties);
} }
} }

View File

@@ -59,49 +59,37 @@ public class ClientRunningTest extends AbstractZkTest {
final ClientRunningMonitor runningMonitor2 = buildClientRunning(countLatch, clientId, 2089); final ClientRunningMonitor runningMonitor2 = buildClientRunning(countLatch, clientId, 2089);
final ClientRunningMonitor runningMonitor3 = buildClientRunning(countLatch, clientId, 2090); final ClientRunningMonitor runningMonitor3 = buildClientRunning(countLatch, clientId, 2090);
final ExecutorService executor = Executors.newFixedThreadPool(3); final ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(new Runnable() { executor.submit(() -> {
for (int i = 0; i < 10; i++) {
public void run() { if (!runningMonitor1.isStart()) {
for (int i = 0; i < 10; i++) { runningMonitor1.start();
if (!runningMonitor1.isStart()) {
runningMonitor1.start();
}
sleep(2000L + RandomUtils.nextInt(500));
runningMonitor1.stop();
sleep(2000L + RandomUtils.nextInt(500));
} }
sleep(2000L + RandomUtils.nextInt(500));
runningMonitor1.stop();
sleep(2000L + RandomUtils.nextInt(500));
} }
}); });
executor.submit(new Runnable() { executor.submit(() -> {
for (int i = 0; i < 10; i++) {
public void run() { if (!runningMonitor2.isStart()) {
for (int i = 0; i < 10; i++) { runningMonitor2.start();
if (!runningMonitor2.isStart()) {
runningMonitor2.start();
}
sleep(2000L + RandomUtils.nextInt(500));
runningMonitor2.stop();
sleep(2000L + RandomUtils.nextInt(500));
} }
sleep(2000L + RandomUtils.nextInt(500));
runningMonitor2.stop();
sleep(2000L + RandomUtils.nextInt(500));
} }
}); });
executor.submit(new Runnable() { executor.submit(() -> {
for (int i = 0; i < 10; i++) {
public void run() { if (!runningMonitor3.isStart()) {
for (int i = 0; i < 10; i++) { runningMonitor3.start();
if (!runningMonitor3.isStart()) {
runningMonitor3.start();
}
sleep(2000L + RandomUtils.nextInt(500));
runningMonitor3.stop();
sleep(2000L + RandomUtils.nextInt(500));
} }
sleep(2000L + RandomUtils.nextInt(500));
runningMonitor3.stop();
sleep(2000L + RandomUtils.nextInt(500));
} }
}); });
sleep(30000L); sleep(30000L);

View File

@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<artifactId>canal</artifactId> <artifactId>canal</artifactId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<artifactId>canal.common</artifactId> <artifactId>canal.common</artifactId>

View File

@@ -18,20 +18,11 @@ public class AddressUtils {
private static final Pattern IP_PATTERN = Pattern.compile("[0-9]{1,3}(\\.[0-9]{1,3}){3,}"); private static final Pattern IP_PATTERN = Pattern.compile("[0-9]{1,3}(\\.[0-9]{1,3}){3,}");
public static boolean isAvailablePort(int port) { public static boolean isAvailablePort(int port) {
ServerSocket ss = null; try (ServerSocket ss = new ServerSocket(port)) {
try {
ss = new ServerSocket(port);
ss.bind(null); ss.bind(null);
return true; return true;
} catch (IOException e) { } catch (IOException e) {
return false; return false;
} finally {
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
}
}
} }
} }

View File

@@ -32,7 +32,7 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
*/ */
public class BooleanMutex { public class BooleanMutex {
private Sync sync; private final Sync sync;
public BooleanMutex(){ public BooleanMutex(){
sync = new Sync(); sync = new Sync();
@@ -47,7 +47,7 @@ public class BooleanMutex {
/** /**
* 阻塞等待Boolean为true * 阻塞等待Boolean为true
* *
* @throws InterruptedException * @throws InterruptedException if the current thread is interrupted
*/ */
public void get() throws InterruptedException { public void get() throws InterruptedException {
sync.innerGet(); sync.innerGet();
@@ -86,7 +86,7 @@ public class BooleanMutex {
* Synchronization control for BooleanMutex. Uses AQS sync state to * Synchronization control for BooleanMutex. Uses AQS sync state to
* represent run status * represent run status
*/ */
private final class Sync extends AbstractQueuedSynchronizer { private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 2559471934544126329L; private static final long serialVersionUID = 2559471934544126329L;
/** State value representing that TRUE */ /** State value representing that TRUE */

View File

@@ -34,7 +34,7 @@ public class ExecutorTemplate {
private volatile List<Future> futures = null; private volatile List<Future> futures = null;
public ExecutorTemplate(ThreadPoolExecutor executor){ public ExecutorTemplate(ThreadPoolExecutor executor){
this.futures = Collections.synchronizedList(new ArrayList<Future>()); this.futures = Collections.synchronizedList(new ArrayList<>());
this.executor = executor; this.executor = executor;
} }

View File

@@ -13,7 +13,6 @@ import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.JSONSerializer; import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.ObjectSerializer; import com.alibaba.fastjson.serializer.ObjectSerializer;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializeConfig; import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializeWriter; import com.alibaba.fastjson.serializer.SerializeWriter;
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.serializer.SerializerFeature;
@@ -72,20 +71,11 @@ public class JsonUtils {
*/ */
public static String marshalToString(Object obj, String... fliterFields) { public static String marshalToString(Object obj, String... fliterFields) {
final List<String> propertyFliters = Arrays.asList(fliterFields); final List<String> propertyFliters = Arrays.asList(fliterFields);
SerializeWriter out = new SerializeWriter(); try (SerializeWriter out = new SerializeWriter()) {
try {
JSONSerializer serializer = new JSONSerializer(out); JSONSerializer serializer = new JSONSerializer(out);
serializer.getPropertyFilters().add(new PropertyFilter() { serializer.getPropertyFilters().add((source, name, value) -> !propertyFliters.contains(name));
public boolean apply(Object source, String name, Object value) {
return !propertyFliters.contains(name);
}
});
serializer.write(obj); serializer.write(obj);
return out.toString(); return out.toString();
} finally {
out.close();
} }
} }

View File

@@ -19,18 +19,14 @@ public class NamedThreadFactory implements ThreadFactory {
final private boolean daemon; final private boolean daemon;
final private ThreadGroup group; final private ThreadGroup group;
final private AtomicInteger threadNumber = new AtomicInteger(0); final private AtomicInteger threadNumber = new AtomicInteger(0);
final static UncaughtExceptionHandler uncaughtExceptionHandler = new UncaughtExceptionHandler() { final static UncaughtExceptionHandler uncaughtExceptionHandler = (t, e) -> {
if (e instanceof InterruptedException
|| (e.getCause() != null && e.getCause() instanceof InterruptedException)) {
return;
}
public void uncaughtException(Thread t, logger.error("from " + t.getName(), e);
Throwable e) { };
if (e instanceof InterruptedException
|| (e.getCause() != null && e.getCause() instanceof InterruptedException)) {
return;
}
logger.error("from " + t.getName(), e);
}
};
public NamedThreadFactory(){ public NamedThreadFactory(){
this(DEFAULT_NAME, true); this(DEFAULT_NAME, true);

View File

@@ -0,0 +1,32 @@
package com.alibaba.otter.canal.common.utils;
import org.apache.commons.lang.StringUtils;
import java.util.Properties;
public class PropertiesUtils {
public static String getProperty(Properties properties, String key, String defaultValue) {
String value = getProperty(properties, key);
if (StringUtils.isEmpty(value)) {
return defaultValue;
} else {
return value;
}
}
public static String getProperty(Properties properties, String key) {
key = StringUtils.trim(key);
String value = System.getProperty(key);
if (value == null) {
value = System.getenv(key);
}
if (value == null) {
value = properties.getProperty(key);
}
return StringUtils.trim(value);
}
}

View File

@@ -53,7 +53,7 @@ public final class UriUtils {
return Collections.EMPTY_MAP; return Collections.EMPTY_MAP;
} }
String query = uri.getRawQuery(); String query = uri.getRawQuery();
HashMap<String, String> params = new HashMap<String, String>(); HashMap<String, String> params = new HashMap<>();
@SuppressWarnings("resource") @SuppressWarnings("resource")
Scanner scan = new Scanner(query); Scanner scan = new Scanner(query);
scan.useDelimiter(SPLIT); scan.useDelimiter(SPLIT);

View File

@@ -11,7 +11,6 @@ import org.I0Itec.zkclient.exception.ZkNodeExistsException;
import org.I0Itec.zkclient.serialize.ZkSerializer; import org.I0Itec.zkclient.serialize.ZkSerializer;
import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.CreateMode;
import com.google.common.base.Function;
import com.google.common.collect.MigrateMap; import com.google.common.collect.MigrateMap;
/** /**
@@ -23,12 +22,7 @@ import com.google.common.collect.MigrateMap;
public class ZkClientx extends ZkClient { public class ZkClientx extends ZkClient {
// 对于zkclient进行一次缓存,避免一个jvm内部使用多个zk connection // 对于zkclient进行一次缓存,避免一个jvm内部使用多个zk connection
private static Map<String, ZkClientx> clients = MigrateMap.makeComputingMap(new Function<String, ZkClientx>() { private static Map<String, ZkClientx> clients = MigrateMap.makeComputingMap(ZkClientx::new);
public ZkClientx apply(String servers) {
return new ZkClientx(servers);
}
});
public static ZkClientx getZkClient(String servers) { public static ZkClientx getZkClient(String servers) {
return clients.get(servers); return clients.get(servers);

View File

@@ -73,12 +73,7 @@ public class ServerRunningMonitor extends AbstractCanalLifeCycle {
initRunning(); initRunning();
} else { } else {
// 否则就是等待delayTime,避免因网络瞬端或者zk异常,导致出现频繁的切换操作 // 否则就是等待delayTime,避免因网络瞬端或者zk异常,导致出现频繁的切换操作
delayExector.schedule(new Runnable() { delayExector.schedule(() -> initRunning(), delayTime, TimeUnit.SECONDS);
public void run() {
initRunning();
}
}, delayTime, TimeUnit.SECONDS);
} }
} }

View File

@@ -24,7 +24,7 @@ public class MigrateMap {
} }
}); });
return new MigrateConcurrentMap<K, V>(computingCache); return new MigrateConcurrentMap<>(computingCache);
} }
public static <K, V> ConcurrentMap<K, V> makeComputingMap(Function<? super K, ? extends V> computingFunction) { public static <K, V> ConcurrentMap<K, V> makeComputingMap(Function<? super K, ? extends V> computingFunction) {

View File

@@ -57,55 +57,43 @@ public class ServerRunningTest extends AbstractZkTest {
final ServerRunningMonitor runningMonitor2 = buildServerRunning(countLatch, "127.0.0.1", 2089); final ServerRunningMonitor runningMonitor2 = buildServerRunning(countLatch, "127.0.0.1", 2089);
final ServerRunningMonitor runningMonitor3 = buildServerRunning(countLatch, "127.0.0.1", 2090); final ServerRunningMonitor runningMonitor3 = buildServerRunning(countLatch, "127.0.0.1", 2090);
final ExecutorService executor = Executors.newFixedThreadPool(3); final ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(new Runnable() { executor.submit(() -> {
for (int i = 0; i < 10; i++) {
public void run() { if (!runningMonitor1.isStart()) {
for (int i = 0; i < 10; i++) { runningMonitor1.start();
if (!runningMonitor1.isStart()) {
runningMonitor1.start();
}
sleep(2000L + RandomUtils.nextInt(500));
if (runningMonitor1.check()) {
runningMonitor1.stop();
}
sleep(2000L + RandomUtils.nextInt(500));
} }
sleep(2000L + RandomUtils.nextInt(500));
if (runningMonitor1.check()) {
runningMonitor1.stop();
}
sleep(2000L + RandomUtils.nextInt(500));
} }
}); });
executor.submit(new Runnable() { executor.submit(() -> {
for (int i = 0; i < 10; i++) {
public void run() { if (!runningMonitor2.isStart()) {
for (int i = 0; i < 10; i++) { runningMonitor2.start();
if (!runningMonitor2.isStart()) {
runningMonitor2.start();
}
sleep(2000L + RandomUtils.nextInt(500));
if (runningMonitor2.check()) {
runningMonitor2.stop();
}
sleep(2000L + RandomUtils.nextInt(500));
} }
sleep(2000L + RandomUtils.nextInt(500));
if (runningMonitor2.check()) {
runningMonitor2.stop();
}
sleep(2000L + RandomUtils.nextInt(500));
} }
}); });
executor.submit(new Runnable() { executor.submit(() -> {
for (int i = 0; i < 10; i++) {
public void run() { if (!runningMonitor3.isStart()) {
for (int i = 0; i < 10; i++) { runningMonitor3.start();
if (!runningMonitor3.isStart()) {
runningMonitor3.start();
}
sleep(2000L + RandomUtils.nextInt(500));
if (runningMonitor3.check()) {
runningMonitor3.stop();
}
sleep(2000L + RandomUtils.nextInt(500));
} }
sleep(2000L + RandomUtils.nextInt(500));
if (runningMonitor3.check()) {
runningMonitor3.stop();
}
sleep(2000L + RandomUtils.nextInt(500));
} }
}); });
sleep(30000L); sleep(30000L);

View File

@@ -0,0 +1,117 @@
package com.alibaba.otter.canal.common.utils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import static org.junit.Assert.*;
public class BooleanMutexTest {
public static final int CONCURRENCY = 10;
private ExecutorService executorService;
@Before
public void setUp() {
executorService = Executors.newFixedThreadPool(CONCURRENCY);
}
@After
public void tearDown() {
if (executorService != null) {
executorService.shutdownNow();
}
}
@Test(timeout = 3000L)
public void testBooleanMutexGet() throws Exception {
BooleanMutex mutex = new BooleanMutex();
AtomicLong atomicLong = new AtomicLong(0);
Phaser phaser = new Phaser(CONCURRENCY + 1);
for (int i = 0; i < CONCURRENCY; i++) {
executorService.submit(() -> {
try {
// arrive phase1 and wait until phase1 finish
int phase1 = phaser.arrive();
phaser.awaitAdvanceInterruptibly(phase1);
mutex.get();
atomicLong.addAndGet(1);
// arrive phase2
phaser.arrive();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
});
}
assertEquals(0, atomicLong.get());
// arrive phase1 and wait until phase1 finish
int phase1 = phaser.arrive();
phaser.awaitAdvanceInterruptibly(phase1);
assertEquals(0, atomicLong.get());
mutex.set(true);
// arrive phase2 and wait until phase2 finish
int phase2 = phaser.arrive();
phaser.awaitAdvanceInterruptibly(phase2);
assertEquals(CONCURRENCY, atomicLong.get());
}
@Test(timeout = 30000L, expected = TimeoutException.class)
public void testBooleanMutexBlock() throws Exception {
BooleanMutex mutex = new BooleanMutex();
AtomicLong atomicLong = new AtomicLong(0);
Phaser phaser = new Phaser(CONCURRENCY + 1);
for (int i = 0; i < CONCURRENCY; i++) {
executorService.submit(() -> {
try {
// arrive phase1 and wait until phase1 finish
int phase1 = phaser.arrive();
phaser.awaitAdvanceInterruptibly(phase1);
mutex.get();
atomicLong.addAndGet(1);
// arrive phase2
phaser.arrive();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
});
}
assertEquals(0, atomicLong.get());
// arrive phase1 and wait until phase1 finish
int phase1 = phaser.arrive();
phaser.awaitAdvanceInterruptibly(phase1);
assertEquals(0, atomicLong.get());
// mutex is still false
mutex.set(false);
// arrive phase2 and wait until phase2 finish
int phase2 = phaser.arrive();
// will throw interrupted exception when timeout because mutex is still false
phaser.awaitAdvanceInterruptibly(phase2, 2, TimeUnit.SECONDS);
fail("unreachable code");
}
}

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.connector</artifactId> <artifactId>canal.connector</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>

View File

@@ -2,7 +2,6 @@ package com.alibaba.otter.canal.connector.core.filter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -42,7 +41,7 @@ public class AviaterRegexFilter {
this.defaultEmptyValue = defaultEmptyValue; this.defaultEmptyValue = defaultEmptyValue;
List<String> list = null; List<String> list = null;
if (StringUtils.isEmpty(pattern)) { if (StringUtils.isEmpty(pattern)) {
list = new ArrayList<String>(); list = new ArrayList<>();
} else { } else {
String[] ss = StringUtils.split(pattern, SPLIT); String[] ss = StringUtils.split(pattern, SPLIT);
list = Arrays.asList(ss); list = Arrays.asList(ss);
@@ -51,7 +50,7 @@ public class AviaterRegexFilter {
// 对pattern按照从长到短的排序 // 对pattern按照从长到短的排序
// 因为 foo|foot 匹配 foot 会出错,原因是 foot 匹配了 foo 之后,会返回 foo,但是 foo 的长度和 foot // 因为 foo|foot 匹配 foot 会出错,原因是 foot 匹配了 foo 之后,会返回 foo,但是 foo 的长度和 foot
// 的长度不一样 // 的长度不一样
Collections.sort(list, COMPARATOR); list.sort(COMPARATOR);
// 对pattern进行头尾完全匹配 // 对pattern进行头尾完全匹配
list = completionPattern(list); list = completionPattern(list);
this.pattern = StringUtils.join(list, PATTERN_SPLIT); this.pattern = StringUtils.join(list, PATTERN_SPLIT);
@@ -66,7 +65,7 @@ public class AviaterRegexFilter {
return defaultEmptyValue; return defaultEmptyValue;
} }
Map<String, Object> env = new HashMap<String, Object>(); Map<String, Object> env = new HashMap<>();
env.put("pattern", pattern); env.put("pattern", pattern);
env.put("target", filtered.toLowerCase()); env.put("target", filtered.toLowerCase());
return (Boolean) exp.execute(env); return (Boolean) exp.execute(env);
@@ -88,13 +87,7 @@ public class AviaterRegexFilter {
@Override @Override
public int compare(String str1, String str2) { public int compare(String str1, String str2) {
if (str1.length() > str2.length()) { return Integer.compare(str2.length(), str1.length());
return -1;
} else if (str1.length() < str2.length()) {
return 1;
} else {
return 0;
}
} }
} }
@@ -112,7 +105,7 @@ public class AviaterRegexFilter {
*/ */
private List<String> completionPattern(List<String> patterns) { private List<String> completionPattern(List<String> patterns) {
List<String> result = new ArrayList<String>(); List<String> result = new ArrayList<>();
for (String pattern : patterns) { for (String pattern : patterns) {
StringBuffer stringBuffer = new StringBuffer(); StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("^"); stringBuffer.append("^");

View File

@@ -1,17 +1,17 @@
package com.alibaba.otter.canal.connector.core.producer; package com.alibaba.otter.canal.connector.core.producer;
import com.alibaba.otter.canal.common.utils.NamedThreadFactory;
import com.alibaba.otter.canal.common.utils.PropertiesUtils;
import com.alibaba.otter.canal.connector.core.config.CanalConstants;
import com.alibaba.otter.canal.connector.core.config.MQProperties;
import com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;
import org.apache.commons.lang.StringUtils;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
import com.alibaba.otter.canal.common.utils.NamedThreadFactory;
import com.alibaba.otter.canal.connector.core.config.CanalConstants;
import com.alibaba.otter.canal.connector.core.config.MQProperties;
import com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;
/** /**
* MQ producer 抽象类 * MQ producer 抽象类
* *
@@ -20,7 +20,7 @@ import com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;
*/ */
public abstract class AbstractMQProducer implements CanalMQProducer { public abstract class AbstractMQProducer implements CanalMQProducer {
protected MQProperties mqProperties; protected MQProperties mqProperties;
protected ThreadPoolExecutor sendExecutor; protected ThreadPoolExecutor sendExecutor;
protected ThreadPoolExecutor buildExecutor; protected ThreadPoolExecutor buildExecutor;
@@ -32,21 +32,21 @@ public abstract class AbstractMQProducer implements CanalMQProducer {
int parallelBuildThreadSize = mqProperties.getParallelBuildThreadSize(); int parallelBuildThreadSize = mqProperties.getParallelBuildThreadSize();
buildExecutor = new ThreadPoolExecutor(parallelBuildThreadSize, buildExecutor = new ThreadPoolExecutor(parallelBuildThreadSize,
parallelBuildThreadSize, parallelBuildThreadSize,
0, 0,
TimeUnit.SECONDS, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(parallelBuildThreadSize * 2), new ArrayBlockingQueue<>(parallelBuildThreadSize * 2),
new NamedThreadFactory("MQ-Parallel-Builder"), new NamedThreadFactory("MQ-Parallel-Builder"),
new ThreadPoolExecutor.CallerRunsPolicy()); new ThreadPoolExecutor.CallerRunsPolicy());
int parallelSendThreadSize = mqProperties.getParallelSendThreadSize(); int parallelSendThreadSize = mqProperties.getParallelSendThreadSize();
sendExecutor = new ThreadPoolExecutor(parallelSendThreadSize, sendExecutor = new ThreadPoolExecutor(parallelSendThreadSize,
parallelSendThreadSize, parallelSendThreadSize,
0, 0,
TimeUnit.SECONDS, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(parallelSendThreadSize * 2), new ArrayBlockingQueue<>(parallelSendThreadSize * 2),
new NamedThreadFactory("MQ-Parallel-Sender"), new NamedThreadFactory("MQ-Parallel-Sender"),
new ThreadPoolExecutor.CallerRunsPolicy()); new ThreadPoolExecutor.CallerRunsPolicy());
} }
@Override @Override
@@ -77,52 +77,52 @@ public abstract class AbstractMQProducer implements CanalMQProducer {
* canal.mq.timeout = 100 <br/> * canal.mq.timeout = 100 <br/>
* canal.mq.access.channel = local <br/> * canal.mq.access.channel = local <br/>
* </p> * </p>
* *
* @param properties 总配置对象 * @param properties 总配置对象
*/ */
private void loadCanalMqProperties(Properties properties) { private void loadCanalMqProperties(Properties properties) {
String flatMessage = properties.getProperty(CanalConstants.CANAL_MQ_FLAT_MESSAGE); String flatMessage = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_FLAT_MESSAGE);
if (!StringUtils.isEmpty(flatMessage)) { if (!StringUtils.isEmpty(flatMessage)) {
mqProperties.setFlatMessage(Boolean.parseBoolean(flatMessage)); mqProperties.setFlatMessage(Boolean.parseBoolean(flatMessage));
} }
String databaseHash = properties.getProperty(CanalConstants.CANAL_MQ_DATABASE_HASH); String databaseHash = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_DATABASE_HASH);
if (!StringUtils.isEmpty(databaseHash)) { if (!StringUtils.isEmpty(databaseHash)) {
mqProperties.setDatabaseHash(Boolean.parseBoolean(databaseHash)); mqProperties.setDatabaseHash(Boolean.parseBoolean(databaseHash));
} }
String filterTranEntry = properties.getProperty(CanalConstants.CANAL_FILTER_TRANSACTION_ENTRY); String filterTranEntry = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_FILTER_TRANSACTION_ENTRY);
if (!StringUtils.isEmpty(filterTranEntry)) { if (!StringUtils.isEmpty(filterTranEntry)) {
mqProperties.setFilterTransactionEntry(Boolean.parseBoolean(filterTranEntry)); mqProperties.setFilterTransactionEntry(Boolean.parseBoolean(filterTranEntry));
} }
String parallelBuildThreadSize = properties.getProperty(CanalConstants.CANAL_MQ_BUILD_THREAD_SIZE); String parallelBuildThreadSize = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_BUILD_THREAD_SIZE);
if (!StringUtils.isEmpty(parallelBuildThreadSize)) { if (!StringUtils.isEmpty(parallelBuildThreadSize)) {
mqProperties.setParallelBuildThreadSize(Integer.parseInt(parallelBuildThreadSize)); mqProperties.setParallelBuildThreadSize(Integer.parseInt(parallelBuildThreadSize));
} }
String parallelSendThreadSize = properties.getProperty(CanalConstants.CANAL_MQ_SEND_THREAD_SIZE); String parallelSendThreadSize = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_SEND_THREAD_SIZE);
if (!StringUtils.isEmpty(parallelSendThreadSize)) { if (!StringUtils.isEmpty(parallelSendThreadSize)) {
mqProperties.setParallelSendThreadSize(Integer.parseInt(parallelSendThreadSize)); mqProperties.setParallelSendThreadSize(Integer.parseInt(parallelSendThreadSize));
} }
String batchSize = properties.getProperty(CanalConstants.CANAL_MQ_CANAL_BATCH_SIZE); String batchSize = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_CANAL_BATCH_SIZE);
if (!StringUtils.isEmpty(batchSize)) { if (!StringUtils.isEmpty(batchSize)) {
mqProperties.setBatchSize(Integer.parseInt(batchSize)); mqProperties.setBatchSize(Integer.parseInt(batchSize));
} }
String timeOut = properties.getProperty(CanalConstants.CANAL_MQ_CANAL_GET_TIMEOUT); String timeOut = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_CANAL_GET_TIMEOUT);
if (!StringUtils.isEmpty(timeOut)) { if (!StringUtils.isEmpty(timeOut)) {
mqProperties.setFetchTimeout(Integer.parseInt(timeOut)); mqProperties.setFetchTimeout(Integer.parseInt(timeOut));
} }
String accessChannel = properties.getProperty(CanalConstants.CANAL_MQ_ACCESS_CHANNEL); String accessChannel = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_ACCESS_CHANNEL);
if (!StringUtils.isEmpty(accessChannel)) { if (!StringUtils.isEmpty(accessChannel)) {
mqProperties.setAccessChannel(accessChannel); mqProperties.setAccessChannel(accessChannel);
} }
String aliyunAccessKey = properties.getProperty(CanalConstants.CANAL_ALIYUN_ACCESS_KEY); String aliyunAccessKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_ACCESS_KEY);
if (!StringUtils.isEmpty(aliyunAccessKey)) { if (!StringUtils.isEmpty(aliyunAccessKey)) {
mqProperties.setAliyunAccessKey(aliyunAccessKey); mqProperties.setAliyunAccessKey(aliyunAccessKey);
} }
String aliyunSecretKey = properties.getProperty(CanalConstants.CANAL_ALIYUN_SECRET_KEY); String aliyunSecretKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_SECRET_KEY);
if (!StringUtils.isEmpty(aliyunSecretKey)) { if (!StringUtils.isEmpty(aliyunSecretKey)) {
mqProperties.setAliyunAccessKey(aliyunSecretKey); mqProperties.setAliyunSecretKey(aliyunSecretKey);
} }
String aliyunUid = properties.getProperty(CanalConstants.CANAL_ALIYUN_UID); String aliyunUid = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_UID);
if (!StringUtils.isEmpty(aliyunUid)) { if (!StringUtils.isEmpty(aliyunUid)) {
mqProperties.setAliyunUid(Integer.parseInt(aliyunUid)); mqProperties.setAliyunUid(Integer.parseInt(aliyunUid));
} }
@@ -132,7 +132,7 @@ public abstract class AbstractMQProducer implements CanalMQProducer {
* 兼容下<=1.1.4的mq配置项 * 兼容下<=1.1.4的mq配置项
*/ */
protected void doMoreCompatibleConvert(String oldKey, String newKey, Properties properties) { protected void doMoreCompatibleConvert(String oldKey, String newKey, Properties properties) {
String value = properties.getProperty(oldKey); String value = PropertiesUtils.getProperty(properties, oldKey);
if (StringUtils.isNotEmpty(value)) { if (StringUtils.isNotEmpty(value)) {
properties.setProperty(newKey, value); properties.setProperty(newKey, value);
} }

View File

@@ -19,7 +19,6 @@ import com.alibaba.otter.canal.protocol.CanalEntry.Entry;
import com.alibaba.otter.canal.protocol.CanalEntry.RowChange; import com.alibaba.otter.canal.protocol.CanalEntry.RowChange;
import com.alibaba.otter.canal.protocol.FlatMessage; import com.alibaba.otter.canal.protocol.FlatMessage;
import com.alibaba.otter.canal.protocol.Message; import com.alibaba.otter.canal.protocol.Message;
import com.google.common.base.Function;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.MigrateMap; import com.google.common.collect.MigrateMap;
@@ -75,64 +74,58 @@ public class MQMessageUtils {
private static Map<String, List<DynamicTopicData>> dynamicTopicDatas = MigrateMap.makeComputingMap(CacheBuilder.newBuilder() private static Map<String, List<DynamicTopicData>> dynamicTopicDatas = MigrateMap.makeComputingMap(CacheBuilder.newBuilder()
.softValues(), .softValues(),
new Function<String, List<DynamicTopicData>>() { pkHashConfigs -> {
List<DynamicTopicData> datas = Lists.newArrayList();
String[] dynamicTopicArray = StringUtils.split(StringUtils.replace(pkHashConfigs,
",",
";"),
";");
// schema.table
for (String dynamicTopic : dynamicTopicArray) {
DynamicTopicData data = new DynamicTopicData();
public List<DynamicTopicData> apply(String pkHashConfigs) { if (!isWildCard(dynamicTopic)) {
List<DynamicTopicData> datas = Lists.newArrayList(); data.simpleName = dynamicTopic;
String[] dynamicTopicArray = StringUtils.split(StringUtils.replace(pkHashConfigs, } else {
",", if (dynamicTopic.contains("\\.")) {
";"), data.tableRegexFilter = new AviaterRegexFilter(dynamicTopic);
";"); } else {
// schema.table data.schemaRegexFilter = new AviaterRegexFilter(dynamicTopic);
for (String dynamicTopic : dynamicTopicArray) { }
DynamicTopicData data = new DynamicTopicData(); }
datas.add(data);
}
if (!isWildCard(dynamicTopic)) { return datas;
data.simpleName = dynamicTopic; });
} else {
if (dynamicTopic.contains("\\.")) {
data.tableRegexFilter = new AviaterRegexFilter(dynamicTopic);
} else {
data.schemaRegexFilter = new AviaterRegexFilter(dynamicTopic);
}
}
datas.add(data);
}
return datas;
}
});
private static Map<String, List<TopicPartitionData>> topicPartitionDatas = MigrateMap.makeComputingMap(CacheBuilder.newBuilder() private static Map<String, List<TopicPartitionData>> topicPartitionDatas = MigrateMap.makeComputingMap(CacheBuilder.newBuilder()
.softValues(), .softValues(),
new Function<String, List<TopicPartitionData>>() { tPConfigs -> {
List<TopicPartitionData> datas = Lists.newArrayList();
public List<TopicPartitionData> apply(String tPConfigs) { String[] tPArray = StringUtils.split(StringUtils.replace(tPConfigs,
List<TopicPartitionData> datas = Lists.newArrayList(); ",",
String[] tPArray = StringUtils.split(StringUtils.replace(tPConfigs, ";"),
",", ";");
";"), for (String tPConfig : tPArray) {
";"); TopicPartitionData data = new TopicPartitionData();
for (String tPConfig : tPArray) { int i = tPConfig.lastIndexOf(":");
TopicPartitionData data = new TopicPartitionData(); if (i > 0) {
int i = tPConfig.lastIndexOf(":"); String tStr = tPConfig.substring(0, i);
if (i > 0) { String pStr = tPConfig.substring(i + 1);
String tStr = tPConfig.substring(0, i); if (!isWildCard(tStr)) {
String pStr = tPConfig.substring(i + 1); data.simpleName = tStr;
if (!isWildCard(tStr)) { } else {
data.simpleName = tStr; data.regexFilter = new AviaterRegexFilter(tStr);
} else {
data.regexFilter = new AviaterRegexFilter(tStr);
}
if (!StringUtils.isEmpty(pStr) && StringUtils.isNumeric(pStr)) {
data.partitionNum = Integer.valueOf(pStr);
}
datas.add(data);
} }
if (!StringUtils.isEmpty(pStr) && StringUtils.isNumeric(pStr)) {
data.partitionNum = Integer.valueOf(pStr);
}
datas.add(data);
} }
return datas;
} }
return datas;
}); });
/** /**
@@ -206,19 +199,15 @@ public class MQMessageUtils {
int i = 0; int i = 0;
for (ByteString byteString : rawEntries) { for (ByteString byteString : rawEntries) {
final int index = i; final int index = i;
template.submit(new Runnable() { template.submit(() -> {
try {
@Override Entry entry = Entry.parseFrom(byteString);
public void run() { RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
try { datas[index] = new EntryRowData();
Entry entry = Entry.parseFrom(byteString); datas[index].entry = entry;
CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue()); datas[index].rowChange = rowChange;
datas[index] = new EntryRowData(); } catch (InvalidProtocolBufferException e) {
datas[index].entry = entry; throw new RuntimeException(e);
datas[index].rowChange = rowChange;
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
} }
}); });
@@ -232,18 +221,14 @@ public class MQMessageUtils {
int i = 0; int i = 0;
for (Entry entry : message.getEntries()) { for (Entry entry : message.getEntries()) {
final int index = i; final int index = i;
template.submit(new Runnable() { template.submit(() -> {
try {
@Override RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
public void run() { datas[index] = new EntryRowData();
try { datas[index].entry = entry;
CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue()); datas[index].rowChange = rowChange;
datas[index] = new EntryRowData(); } catch (InvalidProtocolBufferException e) {
datas[index].entry = entry; throw new RuntimeException(e);
datas[index].rowChange = rowChange;
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
} }
}); });
@@ -679,7 +664,7 @@ public class MQMessageUtils {
CanalEntry.Entry entry) { CanalEntry.Entry entry) {
Message message = messageMap.get(topicName); Message message = messageMap.get(topicName);
if (message == null) { if (message == null) {
message = new Message(messageId, new ArrayList<CanalEntry.Entry>()); message = new Message(messageId, new ArrayList<>());
messageMap.put(topicName, message); messageMap.put(topicName, message);
} }
message.getEntries().add(entry); message.getEntries().add(entry);

View File

@@ -20,6 +20,7 @@ public class URLClassExtensionLoader extends URLClassLoader {
} }
if (name.startsWith("java.") || name.startsWith("org.slf4j.") || name.startsWith("org.apache.logging") if (name.startsWith("java.") || name.startsWith("org.slf4j.") || name.startsWith("org.apache.logging")
|| name.startsWith("org.apache.zookeeper.") || name.startsWith("org.I0Itec.zkclient.")
|| name.startsWith("org.apache.commons.logging.")) { || name.startsWith("org.apache.commons.logging.")) {
// || name.startsWith("org.apache.hadoop.")) // || name.startsWith("org.apache.hadoop."))
// { // {

View File

@@ -34,8 +34,8 @@ public class CanalMessageSerializerUtil {
messageSize += CodedOutputStream.computeInt64Size(1, data.getId()); messageSize += CodedOutputStream.computeInt64Size(1, data.getId());
int dataSize = 0; int dataSize = 0;
for (int i = 0; i < rowEntries.size(); i++) { for (ByteString rowEntry : rowEntries) {
dataSize += CodedOutputStream.computeBytesSizeNoTag(rowEntries.get(i)); dataSize += CodedOutputStream.computeBytesSizeNoTag(rowEntry);
} }
messageSize += dataSize; messageSize += dataSize;
messageSize += 1 * rowEntries.size(); messageSize += 1 * rowEntries.size();
@@ -53,8 +53,8 @@ public class CanalMessageSerializerUtil {
output.writeRawVarint32(messageSize); output.writeRawVarint32(messageSize);
// message // message
output.writeInt64(1, data.getId()); output.writeInt64(1, data.getId());
for (int i = 0; i < rowEntries.size(); i++) { for (ByteString rowEntry : rowEntries) {
output.writeBytes(2, rowEntries.get(i)); output.writeBytes(2, rowEntry);
} }
output.checkNoSpaceLeft(); output.checkNoSpaceLeft();
return body; return body;

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.connector</artifactId> <artifactId>canal.connector</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@@ -9,6 +9,7 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import com.alibaba.otter.canal.common.utils.PropertiesUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.clients.producer.Producer;
@@ -105,15 +106,15 @@ public class CanalKafkaProducer extends AbstractMQProducer implements CanalMQPro
kafkaProperties.put(key, value); kafkaProperties.put(key, value);
} }
} }
String kerberosEnabled = properties.getProperty(KafkaConstants.CANAL_MQ_KAFKA_KERBEROS_ENABLE); String kerberosEnabled = PropertiesUtils.getProperty(properties, KafkaConstants.CANAL_MQ_KAFKA_KERBEROS_ENABLE);
if (!StringUtils.isEmpty(kerberosEnabled)) { if (!StringUtils.isEmpty(kerberosEnabled)) {
kafkaProducerConfig.setKerberosEnabled(Boolean.parseBoolean(kerberosEnabled)); kafkaProducerConfig.setKerberosEnabled(Boolean.parseBoolean(kerberosEnabled));
} }
String krb5File = properties.getProperty(KafkaConstants.CANAL_MQ_KAFKA_KERBEROS_KRB5_FILE); String krb5File = PropertiesUtils.getProperty(properties, KafkaConstants.CANAL_MQ_KAFKA_KERBEROS_KRB5_FILE);
if (!StringUtils.isEmpty(krb5File)) { if (!StringUtils.isEmpty(krb5File)) {
kafkaProducerConfig.setKrb5File(krb5File); kafkaProducerConfig.setKrb5File(krb5File);
} }
String jaasFile = properties.getProperty(KafkaConstants.CANAL_MQ_KAFKA_KERBEROS_JAAS_FILE); String jaasFile = PropertiesUtils.getProperty(properties, KafkaConstants.CANAL_MQ_KAFKA_KERBEROS_JAAS_FILE);
if (!StringUtils.isEmpty(jaasFile)) { if (!StringUtils.isEmpty(jaasFile)) {
kafkaProducerConfig.setJaasFile(jaasFile); kafkaProducerConfig.setJaasFile(jaasFile);
} }

View File

@@ -1,18 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<artifactId>canal</artifactId> <artifactId>canal</artifactId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<artifactId>canal.connector</artifactId> <artifactId>canal.connector</artifactId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>canal connector module for otter ${project.version}</name> <name>canal connector module for otter ${project.version}</name>

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.connector</artifactId> <artifactId>canal.connector</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@@ -8,6 +8,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import com.alibaba.otter.canal.common.utils.PropertiesUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -66,13 +67,13 @@ public class CanalRabbitMQConsumer implements CanalMsgConsumer {
@Override @Override
public void init(Properties properties, String topic, String groupId) { public void init(Properties properties, String topic, String groupId) {
this.nameServer = properties.getProperty("rabbitmq.host"); this.nameServer = PropertiesUtils.getProperty(properties, "rabbitmq.host");
this.vhost = properties.getProperty("rabbitmq.virtual.host"); this.vhost = PropertiesUtils.getProperty(properties, "rabbitmq.virtual.host");
this.queueName = topic; this.queueName = topic;
this.accessKey = properties.getProperty(CanalConstants.CANAL_ALIYUN_ACCESS_KEY); this.accessKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_ACCESS_KEY);
this.secretKey = properties.getProperty(CanalConstants.CANAL_ALIYUN_SECRET_KEY); this.secretKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_SECRET_KEY);
this.username = properties.getProperty(RabbitMQConstants.RABBITMQ_USERNAME); this.username = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_USERNAME);
this.password = properties.getProperty(RabbitMQConstants.RABBITMQ_PASSWORD); this.password = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_PASSWORD);
Long resourceOwnerIdPro = (Long) properties.get(RabbitMQConstants.RABBITMQ_RESOURCE_OWNERID); Long resourceOwnerIdPro = (Long) properties.get(RabbitMQConstants.RABBITMQ_RESOURCE_OWNERID);
if (resourceOwnerIdPro != null) { if (resourceOwnerIdPro != null) {
this.resourceOwnerId = resourceOwnerIdPro; this.resourceOwnerId = resourceOwnerIdPro;
@@ -90,7 +91,15 @@ public class CanalRabbitMQConsumer implements CanalMsgConsumer {
factory.setUsername(username); factory.setUsername(username);
factory.setPassword(password); factory.setPassword(password);
} }
factory.setHost(nameServer); //解析出端口 modified by 16075140
if (nameServer != null && nameServer.contains(":")) {
String[] serverHostAndPort = nameServer.split(":");
factory.setHost(serverHostAndPort[0]);
factory.setPort(Integer.parseInt(serverHostAndPort[1]));
} else {
factory.setHost(nameServer);
}
factory.setAutomaticRecoveryEnabled(true); factory.setAutomaticRecoveryEnabled(true);
factory.setNetworkRecoveryInterval(5000); factory.setNetworkRecoveryInterval(5000);
factory.setVirtualHost(vhost); factory.setVirtualHost(vhost);

View File

@@ -14,6 +14,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.otter.canal.common.CanalException; import com.alibaba.otter.canal.common.CanalException;
import com.alibaba.otter.canal.common.utils.ExecutorTemplate; import com.alibaba.otter.canal.common.utils.ExecutorTemplate;
import com.alibaba.otter.canal.common.utils.PropertiesUtils;
import com.alibaba.otter.canal.connector.core.producer.AbstractMQProducer; import com.alibaba.otter.canal.connector.core.producer.AbstractMQProducer;
import com.alibaba.otter.canal.connector.core.producer.MQDestination; import com.alibaba.otter.canal.connector.core.producer.MQDestination;
import com.alibaba.otter.canal.connector.core.producer.MQMessageUtils; import com.alibaba.otter.canal.connector.core.producer.MQMessageUtils;
@@ -25,6 +26,7 @@ import com.alibaba.otter.canal.connector.rabbitmq.config.RabbitMQConstants;
import com.alibaba.otter.canal.connector.rabbitmq.config.RabbitMQProducerConfig; import com.alibaba.otter.canal.connector.rabbitmq.config.RabbitMQProducerConfig;
import com.alibaba.otter.canal.protocol.FlatMessage; import com.alibaba.otter.canal.protocol.FlatMessage;
import com.alibaba.otter.canal.protocol.Message; import com.alibaba.otter.canal.protocol.Message;
import com.rabbitmq.client.AlreadyClosedException;
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection; import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.ConnectionFactory;
@@ -84,23 +86,23 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
// 兼容下<=1.1.4的mq配置 // 兼容下<=1.1.4的mq配置
doMoreCompatibleConvert("canal.mq.servers", "rabbitmq.host", properties); doMoreCompatibleConvert("canal.mq.servers", "rabbitmq.host", properties);
String host = properties.getProperty(RabbitMQConstants.RABBITMQ_HOST); String host = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_HOST);
if (!StringUtils.isEmpty(host)) { if (!StringUtils.isEmpty(host)) {
rabbitMQProperties.setHost(host); rabbitMQProperties.setHost(host);
} }
String vhost = properties.getProperty(RabbitMQConstants.RABBITMQ_VIRTUAL_HOST); String vhost = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_VIRTUAL_HOST);
if (!StringUtils.isEmpty(vhost)) { if (!StringUtils.isEmpty(vhost)) {
rabbitMQProperties.setVirtualHost(vhost); rabbitMQProperties.setVirtualHost(vhost);
} }
String exchange = properties.getProperty(RabbitMQConstants.RABBITMQ_EXCHANGE); String exchange = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_EXCHANGE);
if (!StringUtils.isEmpty(exchange)) { if (!StringUtils.isEmpty(exchange)) {
rabbitMQProperties.setExchange(exchange); rabbitMQProperties.setExchange(exchange);
} }
String username = properties.getProperty(RabbitMQConstants.RABBITMQ_USERNAME); String username = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_USERNAME);
if (!StringUtils.isEmpty(username)) { if (!StringUtils.isEmpty(username)) {
rabbitMQProperties.setUsername(username); rabbitMQProperties.setUsername(username);
} }
String password = properties.getProperty(RabbitMQConstants.RABBITMQ_PASSWORD); String password = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_PASSWORD);
if (!StringUtils.isEmpty(password)) { if (!StringUtils.isEmpty(password)) {
rabbitMQProperties.setPassword(password); rabbitMQProperties.setPassword(password);
} }
@@ -120,13 +122,7 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
final String topicName = entry.getKey().replace('.', '_'); final String topicName = entry.getKey().replace('.', '_');
final com.alibaba.otter.canal.protocol.Message messageSub = entry.getValue(); final com.alibaba.otter.canal.protocol.Message messageSub = entry.getValue();
template.submit(new Runnable() { template.submit(() -> send(destination, topicName, messageSub));
@Override
public void run() {
send(destination, topicName, messageSub);
}
});
} }
template.waitForResult(); template.waitForResult();
@@ -182,6 +178,8 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
this.connect.close(); this.connect.close();
this.channel.close(); this.channel.close();
super.stop(); super.stop();
} catch (AlreadyClosedException ex) {
logger.error("Connection is already closed", ex);
} catch (IOException | TimeoutException ex) { } catch (IOException | TimeoutException ex) {
throw new CanalException("Stop RabbitMQ producer error", ex); throw new CanalException("Stop RabbitMQ producer error", ex);
} }

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.connector</artifactId> <artifactId>canal.connector</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
@@ -16,7 +14,7 @@
<name>canal connector rocketMQ module for otter ${project.version}</name> <name>canal connector rocketMQ module for otter ${project.version}</name>
<properties> <properties>
<rocketmq_version>4.5.2</rocketmq_version> <rocketmq_version>4.8.0</rocketmq_version>
</properties> </properties>
<dependencies> <dependencies>
@@ -85,7 +83,7 @@
<tasks> <tasks>
<copy todir="${project.basedir}/../../deployer/target/canal/plugin" overwrite="true"> <copy todir="${project.basedir}/../../deployer/target/canal/plugin" overwrite="true">
<fileset dir="${project.basedir}/target" erroronmissingdir="true"> <fileset dir="${project.basedir}/target" erroronmissingdir="true">
<include name="connector.rocketmq-${project.version}-jar-with-dependencies.jar"/> <include name="connector.rocketmq-${project.version}-jar-with-dependencies.jar" />
</fileset> </fileset>
</copy> </copy>
<copy todir="${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin" overwrite="true"> <copy todir="${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin" overwrite="true">

View File

@@ -17,6 +17,7 @@ public class RocketMQConstants {
public static final String ROCKETMQ_NAMESRV_ADDR = ROOT + "." + "namesrv.addr"; public static final String ROCKETMQ_NAMESRV_ADDR = ROOT + "." + "namesrv.addr";
public static final String ROCKETMQ_RETRY_TIMES_WHEN_SEND_FAILED = ROOT + "." + "retry.times.when.send.failed"; public static final String ROCKETMQ_RETRY_TIMES_WHEN_SEND_FAILED = ROOT + "." + "retry.times.when.send.failed";
public static final String ROCKETMQ_VIP_CHANNEL_ENABLED = ROOT + "." + "vip.channel.enabled"; public static final String ROCKETMQ_VIP_CHANNEL_ENABLED = ROOT + "." + "vip.channel.enabled";
public static final String ROCKETMQ_TAG = ROOT + "." + "tag";
public static final String ROCKETMQ_ACCESS_CHANNEL = ROOT + "." + "access.channel"; public static final String ROCKETMQ_ACCESS_CHANNEL = ROOT + "." + "access.channel";
public static final String ROCKETMQ_BATCH_SIZE = ROOT + "." + "batch.size"; public static final String ROCKETMQ_BATCH_SIZE = ROOT + "." + "batch.size";

View File

@@ -17,6 +17,7 @@ public class RocketMQProducerConfig extends MQProperties {
private String namesrvAddr; private String namesrvAddr;
private int retryTimesWhenSendFailed = 0; private int retryTimesWhenSendFailed = 0;
private boolean vipChannelEnabled = false; private boolean vipChannelEnabled = false;
private String tag;
public String getProducerGroup() { public String getProducerGroup() {
return producerGroup; return producerGroup;
@@ -73,4 +74,12 @@ public class RocketMQProducerConfig extends MQProperties {
public void setVipChannelEnabled(boolean vipChannelEnabled) { public void setVipChannelEnabled(boolean vipChannelEnabled) {
this.vipChannelEnabled = vipChannelEnabled; this.vipChannelEnabled = vipChannelEnabled;
} }
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
} }

View File

@@ -4,6 +4,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@@ -25,6 +28,8 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.otter.canal.common.CanalException; import com.alibaba.otter.canal.common.CanalException;
import com.alibaba.otter.canal.common.utils.ExecutorTemplate; import com.alibaba.otter.canal.common.utils.ExecutorTemplate;
import com.alibaba.otter.canal.common.utils.NamedThreadFactory;
import com.alibaba.otter.canal.common.utils.PropertiesUtils;
import com.alibaba.otter.canal.connector.core.producer.AbstractMQProducer; import com.alibaba.otter.canal.connector.core.producer.AbstractMQProducer;
import com.alibaba.otter.canal.connector.core.producer.MQDestination; import com.alibaba.otter.canal.connector.core.producer.MQDestination;
import com.alibaba.otter.canal.connector.core.producer.MQMessageUtils; import com.alibaba.otter.canal.connector.core.producer.MQMessageUtils;
@@ -45,10 +50,11 @@ import com.alibaba.otter.canal.protocol.FlatMessage;
@SPI("rocketmq") @SPI("rocketmq")
public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQProducer { public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQProducer {
private static final Logger logger = LoggerFactory.getLogger(CanalRocketMQProducer.class); private static final Logger logger = LoggerFactory.getLogger(CanalRocketMQProducer.class);
private DefaultMQProducer defaultMQProducer; private DefaultMQProducer defaultMQProducer;
private static final String CLOUD_ACCESS_CHANNEL = "cloud"; private static final String CLOUD_ACCESS_CHANNEL = "cloud";
protected ThreadPoolExecutor sendPartitionExecutor;
@Override @Override
public void init(Properties properties) { public void init(Properties properties) {
@@ -84,6 +90,15 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
} catch (MQClientException ex) { } catch (MQClientException ex) {
throw new CanalException("Start RocketMQ producer error", ex); throw new CanalException("Start RocketMQ producer error", ex);
} }
int parallelPartitionSendThreadSize = mqProperties.getParallelSendThreadSize();
sendPartitionExecutor = new ThreadPoolExecutor(parallelPartitionSendThreadSize,
parallelPartitionSendThreadSize,
0,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(parallelPartitionSendThreadSize * 2),
new NamedThreadFactory("MQ-Parallel-Sender-Partition"),
new ThreadPoolExecutor.CallerRunsPolicy());
} }
private void loadRocketMQProperties(Properties properties) { private void loadRocketMQProperties(Properties properties) {
@@ -94,34 +109,41 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
doMoreCompatibleConvert("canal.mq.namespace", "rocketmq.namespace", properties); doMoreCompatibleConvert("canal.mq.namespace", "rocketmq.namespace", properties);
doMoreCompatibleConvert("canal.mq.retries", "rocketmq.retry.times.when.send.failed", properties); doMoreCompatibleConvert("canal.mq.retries", "rocketmq.retry.times.when.send.failed", properties);
String producerGroup = properties.getProperty(RocketMQConstants.ROCKETMQ_PRODUCER_GROUP); String producerGroup = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_PRODUCER_GROUP);
if (!StringUtils.isEmpty(producerGroup)) { if (!StringUtils.isEmpty(producerGroup)) {
rocketMQProperties.setProducerGroup(producerGroup); rocketMQProperties.setProducerGroup(producerGroup);
} }
String enableMessageTrace = properties.getProperty(RocketMQConstants.ROCKETMQ_ENABLE_MESSAGE_TRACE); String enableMessageTrace = PropertiesUtils.getProperty(properties,
RocketMQConstants.ROCKETMQ_ENABLE_MESSAGE_TRACE);
if (!StringUtils.isEmpty(enableMessageTrace)) { if (!StringUtils.isEmpty(enableMessageTrace)) {
rocketMQProperties.setEnableMessageTrace(Boolean.parseBoolean(enableMessageTrace)); rocketMQProperties.setEnableMessageTrace(Boolean.parseBoolean(enableMessageTrace));
} }
String customizedTraceTopic = properties.getProperty(RocketMQConstants.ROCKETMQ_CUSTOMIZED_TRACE_TOPIC); String customizedTraceTopic = PropertiesUtils.getProperty(properties,
RocketMQConstants.ROCKETMQ_CUSTOMIZED_TRACE_TOPIC);
if (!StringUtils.isEmpty(customizedTraceTopic)) { if (!StringUtils.isEmpty(customizedTraceTopic)) {
rocketMQProperties.setCustomizedTraceTopic(customizedTraceTopic); rocketMQProperties.setCustomizedTraceTopic(customizedTraceTopic);
} }
String namespace = properties.getProperty(RocketMQConstants.ROCKETMQ_NAMESPACE); String namespace = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_NAMESPACE);
if (!StringUtils.isEmpty(namespace)) { if (!StringUtils.isEmpty(namespace)) {
rocketMQProperties.setNamespace(namespace); rocketMQProperties.setNamespace(namespace);
} }
String namesrvAddr = properties.getProperty(RocketMQConstants.ROCKETMQ_NAMESRV_ADDR); String namesrvAddr = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_NAMESRV_ADDR);
if (!StringUtils.isEmpty(namesrvAddr)) { if (!StringUtils.isEmpty(namesrvAddr)) {
rocketMQProperties.setNamesrvAddr(namesrvAddr); rocketMQProperties.setNamesrvAddr(namesrvAddr);
} }
String retry = properties.getProperty(RocketMQConstants.ROCKETMQ_RETRY_TIMES_WHEN_SEND_FAILED); String retry = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_RETRY_TIMES_WHEN_SEND_FAILED);
if (!StringUtils.isEmpty(retry)) { if (!StringUtils.isEmpty(retry)) {
rocketMQProperties.setRetryTimesWhenSendFailed(Integer.parseInt(retry)); rocketMQProperties.setRetryTimesWhenSendFailed(Integer.parseInt(retry));
} }
String vipChannelEnabled = properties.getProperty(RocketMQConstants.ROCKETMQ_VIP_CHANNEL_ENABLED); String vipChannelEnabled = PropertiesUtils.getProperty(properties,
RocketMQConstants.ROCKETMQ_VIP_CHANNEL_ENABLED);
if (!StringUtils.isEmpty(vipChannelEnabled)) { if (!StringUtils.isEmpty(vipChannelEnabled)) {
rocketMQProperties.setVipChannelEnabled(Boolean.parseBoolean(vipChannelEnabled)); rocketMQProperties.setVipChannelEnabled(Boolean.parseBoolean(vipChannelEnabled));
} }
String tag = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_TAG);
if (!StringUtils.isEmpty(tag)) {
rocketMQProperties.setTag(tag);
}
} }
@Override @Override
@@ -162,7 +184,8 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
public void send(final MQDestination destination, String topicName, com.alibaba.otter.canal.protocol.Message message) { public void send(final MQDestination destination, String topicName, com.alibaba.otter.canal.protocol.Message message) {
// 获取当前topic的分区数 // 获取当前topic的分区数
Integer partitionNum = MQMessageUtils.parseDynamicTopicPartition(topicName, destination.getDynamicTopicPartitionNum()); Integer partitionNum = MQMessageUtils.parseDynamicTopicPartition(topicName,
destination.getDynamicTopicPartitionNum());
if (partitionNum == null) { if (partitionNum == null) {
partitionNum = destination.getPartitionsNum(); partitionNum = destination.getPartitionsNum();
} }
@@ -178,14 +201,16 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
mqProperties.isDatabaseHash()); mqProperties.isDatabaseHash());
int length = messages.length; int length = messages.length;
ExecutorTemplate template = new ExecutorTemplate(sendExecutor); ExecutorTemplate template = new ExecutorTemplate(sendPartitionExecutor);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
com.alibaba.otter.canal.protocol.Message dataPartition = messages[i]; com.alibaba.otter.canal.protocol.Message dataPartition = messages[i];
if (dataPartition != null) { if (dataPartition != null) {
final int index = i; final int index = i;
template.submit(() -> { template.submit(() -> {
Message data = new Message(topicName, CanalMessageSerializerUtil.serializer(dataPartition, Message data = new Message(topicName,
mqProperties.isFilterTransactionEntry())); ((RocketMQProducerConfig) this.mqProperties).getTag(),
CanalMessageSerializerUtil.serializer(dataPartition,
mqProperties.isFilterTransactionEntry()));
sendMessage(data, index); sendMessage(data, index);
}); });
} }
@@ -194,8 +219,9 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
template.waitForResult(); template.waitForResult();
} else { } else {
final int partition = destination.getPartition() != null ? destination.getPartition() : 0; final int partition = destination.getPartition() != null ? destination.getPartition() : 0;
Message data = new Message(topicName, CanalMessageSerializerUtil.serializer(message, Message data = new Message(topicName,
mqProperties.isFilterTransactionEntry())); ((RocketMQProducerConfig) this.mqProperties).getTag(),
CanalMessageSerializerUtil.serializer(message, mqProperties.isFilterTransactionEntry()));
sendMessage(data, partition); sendMessage(data, partition);
} }
} else { } else {
@@ -217,19 +243,23 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
mqProperties.isDatabaseHash()); mqProperties.isDatabaseHash());
int length = partitionFlatMessage.length; int length = partitionFlatMessage.length;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
partitionFlatMessages.get(i).add(partitionFlatMessage[i]); // 增加null判断,issue #3267
if (partitionFlatMessage[i] != null) {
partitionFlatMessages.get(i).add(partitionFlatMessage[i]);
}
} }
} }
ExecutorTemplate template = new ExecutorTemplate(sendExecutor); ExecutorTemplate template = new ExecutorTemplate(sendPartitionExecutor);
for (int i = 0; i < partitionFlatMessages.size(); i++) { for (int i = 0; i < partitionFlatMessages.size(); i++) {
final List<FlatMessage> flatMessagePart = partitionFlatMessages.get(i); final List<FlatMessage> flatMessagePart = partitionFlatMessages.get(i);
if (flatMessagePart != null) { if (flatMessagePart != null && flatMessagePart.size() > 0) {
final int index = i; final int index = i;
template.submit(() -> { template.submit(() -> {
List<Message> messages = flatMessagePart.stream() List<Message> messages = flatMessagePart.stream()
.map(flatMessage -> new Message(topicName, JSON.toJSONBytes(flatMessage, .map(flatMessage -> new Message(topicName,
SerializerFeature.WriteMapNullValue))) ((RocketMQProducerConfig) this.mqProperties).getTag(),
JSON.toJSONBytes(flatMessage, SerializerFeature.WriteMapNullValue)))
.collect(Collectors.toList()); .collect(Collectors.toList());
// 批量发送 // 批量发送
sendMessage(messages, index); sendMessage(messages, index);
@@ -242,8 +272,9 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
} else { } else {
final int partition = destination.getPartition() != null ? destination.getPartition() : 0; final int partition = destination.getPartition() != null ? destination.getPartition() : 0;
List<Message> messages = flatMessages.stream() List<Message> messages = flatMessages.stream()
.map(flatMessage -> new Message(topicName, JSON.toJSONBytes(flatMessage, .map(flatMessage -> new Message(topicName,
SerializerFeature.WriteMapNullValue))) ((RocketMQProducerConfig) this.mqProperties).getTag(),
JSON.toJSONBytes(flatMessage, SerializerFeature.WriteMapNullValue)))
.collect(Collectors.toList()); .collect(Collectors.toList());
// 批量发送 // 批量发送
sendMessage(messages, partition); sendMessage(messages, partition);
@@ -315,6 +346,10 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
public void stop() { public void stop() {
logger.info("## Stop RocketMQ producer##"); logger.info("## Stop RocketMQ producer##");
this.defaultMQProducer.shutdown(); this.defaultMQProducer.shutdown();
if (sendPartitionExecutor != null) {
sendPartitionExecutor.shutdownNow();
}
super.stop(); super.stop();
} }
} }

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>canal.connector</artifactId> <artifactId>canal.connector</artifactId>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
@@ -107,10 +105,9 @@
</goals> </goals>
<configuration> <configuration>
<tasks> <tasks>
<copy todir="${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin" <copy todir="${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin" overwrite="true">
overwrite="true">
<fileset dir="${project.basedir}/target" erroronmissingdir="true"> <fileset dir="${project.basedir}/target" erroronmissingdir="true">
<include name="connector.tcp-${project.version}-jar-with-dependencies.jar"/> <include name="connector.tcp-${project.version}-jar-with-dependencies.jar" />
</fileset> </fileset>
</copy> </copy>
</tasks> </tasks>

View File

@@ -1,11 +1,5 @@
package com.alibaba.otter.canal.connector.tcp.consumer; package com.alibaba.otter.canal.connector.tcp.consumer;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import com.alibaba.otter.canal.client.CanalConnector; import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.impl.ClusterCanalConnector; import com.alibaba.otter.canal.client.impl.ClusterCanalConnector;
import com.alibaba.otter.canal.client.impl.ClusterNodeAccessStrategy; import com.alibaba.otter.canal.client.impl.ClusterNodeAccessStrategy;
@@ -18,11 +12,21 @@ import com.alibaba.otter.canal.connector.core.util.MessageUtil;
import com.alibaba.otter.canal.connector.tcp.config.TCPConstants; import com.alibaba.otter.canal.connector.tcp.config.TCPConstants;
import com.alibaba.otter.canal.protocol.Message; import com.alibaba.otter.canal.protocol.Message;
import org.apache.commons.lang.StringUtils;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
/** /**
* TCP 消费者连接器, 一个destination对应一个SPI实例 * TCP 消费者连接器, 一个destination对应一个SPI实例
* *
* @author rewerma 2020-01-30 * @author rewerma 2020-01-30
* @version 1.0.0 * @author XuDaojie
* @version 1.1.5
* @since 1.1.5
*/ */
@SPI("tcp") @SPI("tcp")
public class CanalTCPConsumer implements CanalMsgConsumer { public class CanalTCPConsumer implements CanalMsgConsumer {
@@ -42,7 +46,7 @@ public class CanalTCPConsumer implements CanalMsgConsumer {
if (batchSizePro != null) { if (batchSizePro != null) {
batchSize = Integer.parseInt(batchSizePro); batchSize = Integer.parseInt(batchSizePro);
} }
if (host != null) { if (StringUtils.isNotBlank(host)) {
String[] ipPort = host.split(":"); String[] ipPort = host.split(":");
SocketAddress sa = new InetSocketAddress(ipPort[0], Integer.parseInt(ipPort[1])); SocketAddress sa = new InetSocketAddress(ipPort[0], Integer.parseInt(ipPort[1]));
this.canalConnector = new SimpleCanalConnector(sa, username, password, destination); this.canalConnector = new SimpleCanalConnector(sa, username, password, destination);

View File

@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>
<artifactId>canal</artifactId> <artifactId>canal</artifactId>
<version>1.1.5-SNAPSHOT</version> <version>1.1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>com.alibaba.otter</groupId> <groupId>com.alibaba.otter</groupId>

View File

@@ -420,11 +420,27 @@ public class JsonConversion {
for (int i = 0; i < endIndex; ++i) { for (int i = 0; i < endIndex; ++i) {
char c = data.charAt(i); char c = data.charAt(i);
if (c == '"') { if (c == '"') {
sb.append('\\'); sb.append("\\\"");
} else if (c == '\n') {
sb.append("\\n");
} else if (c == '\r') {
sb.append("\\r");
} else if (c == '\\') { } else if (c == '\\') {
sb.append("\\"); sb.append("\\\\");
} else if (c == '\t') {
sb.append("\\t");
} else if (c < 16) {
sb.append("\\u000");
sb.append(Integer.toHexString(c));
} else if (c < 32) {
sb.append("\\u00");
sb.append(Integer.toHexString(c));
} else if (c >= 0x7f && c <= 0xA0) {
sb.append("\\u00");
sb.append(Integer.toHexString(c));
} else {
sb.append(c);
} }
sb.append(c);
} }
return sb; return sb;
} }

View File

@@ -37,7 +37,7 @@ public class JsonDiffConversion {
public static StringBuilder print_json_diff(LogBuffer buffer, long len, String columnName, int columnIndex, public static StringBuilder print_json_diff(LogBuffer buffer, long len, String columnName, int columnIndex,
String charsetName) { String charsetName) {
int position = buffer.position(); int position = buffer.position();
List<String> operation_names = new ArrayList<String>(); List<String> operation_names = new ArrayList<>();
while (buffer.hasRemaining()) { while (buffer.hasRemaining()) {
int operation_int = buffer.getUint8(); int operation_int = buffer.getUint8();
if (operation_int >= JSON_DIFF_OPERATION_COUNT) { if (operation_int >= JSON_DIFF_OPERATION_COUNT) {

View File

@@ -16,7 +16,7 @@ import com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent;
*/ */
public final class LogContext { public final class LogContext {
private final Map<Long, TableMapLogEvent> mapOfTable = new HashMap<Long, TableMapLogEvent>(); private final Map<Long, TableMapLogEvent> mapOfTable = new HashMap<>();
private FormatDescriptionLogEvent formatDescription; private FormatDescriptionLogEvent formatDescription;
@@ -24,7 +24,7 @@ public final class LogContext {
private GTIDSet gtidSet; private GTIDSet gtidSet;
private GtidLogEvent gtidLogEvent; // save current gtid log event private LogEvent gtidLogEvent; // save current gtid log event
public LogContext(){ public LogContext(){
this.formatDescription = FormatDescriptionLogEvent.FORMAT_DESCRIPTION_EVENT_5_x; this.formatDescription = FormatDescriptionLogEvent.FORMAT_DESCRIPTION_EVENT_5_x;
@@ -75,11 +75,11 @@ public final class LogContext {
this.gtidSet = gtidSet; this.gtidSet = gtidSet;
} }
public GtidLogEvent getGtidLogEvent() { public LogEvent getGtidLogEvent() {
return gtidLogEvent; return gtidLogEvent;
} }
public void setGtidLogEvent(GtidLogEvent gtidLogEvent) { public void setGtidLogEvent(LogEvent gtidLogEvent) {
this.gtidLogEvent = gtidLogEvent; this.gtidLogEvent = gtidLogEvent;
} }
} }

View File

@@ -162,7 +162,7 @@ public final class LogDecoder {
buffer.limit(header.getEventLen() - LogEvent.BINLOG_CHECKSUM_LEN); buffer.limit(header.getEventLen() - LogEvent.BINLOG_CHECKSUM_LEN);
} }
GTIDSet gtidSet = context.getGtidSet(); GTIDSet gtidSet = context.getGtidSet();
GtidLogEvent gtidLogEvent = context.getGtidLogEvent(); LogEvent gtidLogEvent = context.getGtidLogEvent();
switch (header.getType()) { switch (header.getType()) {
case LogEvent.QUERY_EVENT: { case LogEvent.QUERY_EVENT: {
QueryLogEvent event = new QueryLogEvent(header, buffer, descriptionEvent); QueryLogEvent event = new QueryLogEvent(header, buffer, descriptionEvent);
@@ -185,7 +185,8 @@ public final class LogDecoder {
context.putTable(mapEvent); context.putTable(mapEvent);
return mapEvent; return mapEvent;
} }
case LogEvent.WRITE_ROWS_EVENT_V1: { case LogEvent.WRITE_ROWS_EVENT_V1:
case LogEvent.WRITE_ROWS_EVENT: {
RowsLogEvent event = new WriteRowsLogEvent(header, buffer, descriptionEvent); RowsLogEvent event = new WriteRowsLogEvent(header, buffer, descriptionEvent);
/* updating position in context */ /* updating position in context */
logPosition.position = header.getLogPos(); logPosition.position = header.getLogPos();
@@ -193,7 +194,8 @@ public final class LogDecoder {
header.putGtid(context.getGtidSet(), gtidLogEvent); header.putGtid(context.getGtidSet(), gtidLogEvent);
return event; return event;
} }
case LogEvent.UPDATE_ROWS_EVENT_V1: { case LogEvent.UPDATE_ROWS_EVENT_V1:
case LogEvent.UPDATE_ROWS_EVENT: {
RowsLogEvent event = new UpdateRowsLogEvent(header, buffer, descriptionEvent); RowsLogEvent event = new UpdateRowsLogEvent(header, buffer, descriptionEvent);
/* updating position in context */ /* updating position in context */
logPosition.position = header.getLogPos(); logPosition.position = header.getLogPos();
@@ -201,7 +203,8 @@ public final class LogDecoder {
header.putGtid(context.getGtidSet(), gtidLogEvent); header.putGtid(context.getGtidSet(), gtidLogEvent);
return event; return event;
} }
case LogEvent.DELETE_ROWS_EVENT_V1: { case LogEvent.DELETE_ROWS_EVENT_V1:
case LogEvent.DELETE_ROWS_EVENT: {
RowsLogEvent event = new DeleteRowsLogEvent(header, buffer, descriptionEvent); RowsLogEvent event = new DeleteRowsLogEvent(header, buffer, descriptionEvent);
/* updating position in context */ /* updating position in context */
logPosition.position = header.getLogPos(); logPosition.position = header.getLogPos();
@@ -349,30 +352,6 @@ public final class LogDecoder {
header.putGtid(context.getGtidSet(), gtidLogEvent); header.putGtid(context.getGtidSet(), gtidLogEvent);
return event; return event;
} }
case LogEvent.WRITE_ROWS_EVENT: {
RowsLogEvent event = new WriteRowsLogEvent(header, buffer, descriptionEvent);
/* updating position in context */
logPosition.position = header.getLogPos();
event.fillTable(context);
header.putGtid(context.getGtidSet(), gtidLogEvent);
return event;
}
case LogEvent.UPDATE_ROWS_EVENT: {
RowsLogEvent event = new UpdateRowsLogEvent(header, buffer, descriptionEvent);
/* updating position in context */
logPosition.position = header.getLogPos();
event.fillTable(context);
header.putGtid(context.getGtidSet(), gtidLogEvent);
return event;
}
case LogEvent.DELETE_ROWS_EVENT: {
RowsLogEvent event = new DeleteRowsLogEvent(header, buffer, descriptionEvent);
/* updating position in context */
logPosition.position = header.getLogPos();
event.fillTable(context);
header.putGtid(context.getGtidSet(), gtidLogEvent);
return event;
}
case LogEvent.PARTIAL_UPDATE_ROWS_EVENT: { case LogEvent.PARTIAL_UPDATE_ROWS_EVENT: {
RowsLogEvent event = new UpdateRowsLogEvent(header, buffer, descriptionEvent, true); RowsLogEvent event = new UpdateRowsLogEvent(header, buffer, descriptionEvent, true);
/* updating position in context */ /* updating position in context */
@@ -436,12 +415,26 @@ public final class LogDecoder {
MariaGtidLogEvent event = new MariaGtidLogEvent(header, buffer, descriptionEvent); MariaGtidLogEvent event = new MariaGtidLogEvent(header, buffer, descriptionEvent);
/* updating position in context */ /* updating position in context */
logPosition.position = header.getLogPos(); logPosition.position = header.getLogPos();
if (gtidSet != null) {
gtidSet.update(event.getGtidStr());
// update latest gtid
header.putGtid(gtidSet, event);
}
// update current gtid event to context
context.setGtidLogEvent(event);
return event; return event;
} }
case LogEvent.GTID_LIST_EVENT: { case LogEvent.GTID_LIST_EVENT: {
MariaGtidListLogEvent event = new MariaGtidListLogEvent(header, buffer, descriptionEvent); MariaGtidListLogEvent event = new MariaGtidListLogEvent(header, buffer, descriptionEvent);
/* updating position in context */ /* updating position in context */
logPosition.position = header.getLogPos(); logPosition.position = header.getLogPos();
if (gtidSet != null) {
gtidSet.update(event.getGtidStr());
// update latest gtid
header.putGtid(gtidSet, event);
}
// update current gtid event to context
context.setGtidLogEvent(event);
return event; return event;
} }
case LogEvent.START_ENCRYPTION_EVENT: { case LogEvent.START_ENCRYPTION_EVENT: {

View File

@@ -316,10 +316,11 @@ public final class LogHeader {
return gtidMap.get(CURRENT_GTID_LAST_COMMIT); return gtidMap.get(CURRENT_GTID_LAST_COMMIT);
} }
public void putGtid(GTIDSet gtidSet, GtidLogEvent event) { public void putGtid(GTIDSet gtidSet, LogEvent gtidEvent) {
if (gtidSet != null) { if (gtidSet != null) {
gtidMap.put(GTID_SET_STRING, gtidSet.toString()); gtidMap.put(GTID_SET_STRING, gtidSet.toString());
if (event != null) { if (gtidEvent != null && gtidEvent instanceof GtidLogEvent) {
GtidLogEvent event = (GtidLogEvent)gtidEvent;
gtidMap.put(CURRENT_GTID_STRING, event.getGtidStr()); gtidMap.put(CURRENT_GTID_STRING, event.getGtidStr());
gtidMap.put(CURRENT_GTID_SN, String.valueOf(event.getSequenceNumber())); gtidMap.put(CURRENT_GTID_SN, String.valueOf(event.getSequenceNumber()));
gtidMap.put(CURRENT_GTID_LAST_COMMIT, String.valueOf(event.getLastCommitted())); gtidMap.put(CURRENT_GTID_LAST_COMMIT, String.valueOf(event.getLastCommitted()));

View File

@@ -601,7 +601,7 @@ public final class TableMapLogEvent extends LogEvent {
private void parse_signedness(LogBuffer buffer, int length) { private void parse_signedness(LogBuffer buffer, int length) {
// stores the signedness flags extracted from field // stores the signedness flags extracted from field
List<Boolean> datas = new ArrayList<Boolean>(); List<Boolean> datas = new ArrayList<>();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
int ut = buffer.getUint8(); int ut = buffer.getUint8();
for (int c = 0x80; c != 0; c >>= 1) { for (int c = 0x80; c != 0; c >>= 1) {
@@ -622,7 +622,7 @@ public final class TableMapLogEvent extends LogEvent {
// stores collation numbers extracted from field. // stores collation numbers extracted from field.
int limit = buffer.position() + length; int limit = buffer.position() + length;
this.default_charset = (int) buffer.getPackedLong(); this.default_charset = (int) buffer.getPackedLong();
List<TableMapLogEvent.Pair> datas = new ArrayList<TableMapLogEvent.Pair>(); List<TableMapLogEvent.Pair> datas = new ArrayList<>();
while (buffer.hasRemaining() && buffer.position() < limit) { while (buffer.hasRemaining() && buffer.position() < limit) {
int col_index = (int) buffer.getPackedLong(); int col_index = (int) buffer.getPackedLong();
int col_charset = (int) buffer.getPackedLong(); int col_charset = (int) buffer.getPackedLong();
@@ -639,7 +639,7 @@ public final class TableMapLogEvent extends LogEvent {
private List<Integer> parse_column_charset(LogBuffer buffer, int length) { private List<Integer> parse_column_charset(LogBuffer buffer, int length) {
// stores collation numbers extracted from field. // stores collation numbers extracted from field.
int limit = buffer.position() + length; int limit = buffer.position() + length;
List<Integer> datas = new ArrayList<Integer>(); List<Integer> datas = new ArrayList<>();
while (buffer.hasRemaining() && buffer.position() < limit) { while (buffer.hasRemaining() && buffer.position() < limit) {
int col_charset = (int) buffer.getPackedLong(); int col_charset = (int) buffer.getPackedLong();
datas.add(col_charset); datas.add(col_charset);
@@ -664,10 +664,10 @@ public final class TableMapLogEvent extends LogEvent {
// into a string separate vector. All of them are stored // into a string separate vector. All of them are stored
// in 'vec'. // in 'vec'.
int limit = buffer.position() + length; int limit = buffer.position() + length;
List<List<String>> datas = new ArrayList<List<String>>(); List<List<String>> datas = new ArrayList<>();
while (buffer.hasRemaining() && buffer.position() < limit) { while (buffer.hasRemaining() && buffer.position() < limit) {
int count = (int) buffer.getPackedLong(); int count = (int) buffer.getPackedLong();
List<String> data = new ArrayList<String>(count); List<String> data = new ArrayList<>(count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int len1 = (int) buffer.getPackedLong(); int len1 = (int) buffer.getPackedLong();
data.add(buffer.getFixString(len1)); data.add(buffer.getFixString(len1));
@@ -694,7 +694,7 @@ public final class TableMapLogEvent extends LogEvent {
// stores geometry column's types extracted from field. // stores geometry column's types extracted from field.
int limit = buffer.position() + length; int limit = buffer.position() + length;
List<Integer> datas = new ArrayList<Integer>(); List<Integer> datas = new ArrayList<>();
while (buffer.hasRemaining() && buffer.position() < limit) { while (buffer.hasRemaining() && buffer.position() < limit) {
int col_type = (int) buffer.getPackedLong(); int col_type = (int) buffer.getPackedLong();
datas.add(col_type); datas.add(col_type);

View File

@@ -1,6 +1,9 @@
package com.taobao.tddl.dbsync.binlog.event.mariadb; package com.taobao.tddl.dbsync.binlog.event.mariadb;
import com.alibaba.otter.canal.parse.driver.mysql.packets.MariaGTIDSet;
import com.alibaba.otter.canal.parse.driver.mysql.packets.MariaGtid;
import com.taobao.tddl.dbsync.binlog.LogBuffer; import com.taobao.tddl.dbsync.binlog.LogBuffer;
import com.taobao.tddl.dbsync.binlog.LogEvent;
import com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent; import com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;
import com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent; import com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent;
import com.taobao.tddl.dbsync.binlog.event.LogHeader; import com.taobao.tddl.dbsync.binlog.event.LogHeader;
@@ -11,11 +14,36 @@ import com.taobao.tddl.dbsync.binlog.event.LogHeader;
* @author jianghang 2014-1-20 下午4:51:50 * @author jianghang 2014-1-20 下午4:51:50
* @since 1.0.17 * @since 1.0.17
*/ */
public class MariaGtidListLogEvent extends IgnorableLogEvent { public class MariaGtidListLogEvent extends LogEvent {
private MariaGTIDSet mariaGTIDSet;
/**
* <pre>
* mariadb gtidListLog event format
* uint<4> Number of GTIDs
* GTID[0]
* uint<4> Replication Domain ID
* uint<4> Server_ID
* uint<8> GTID sequence ...
* GTID[n]
* </pre>
* @param header
* @param buffer
* @param descriptionEvent
*/
public MariaGtidListLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){ public MariaGtidListLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){
super(header, buffer, descriptionEvent); super(header);
// do nothing , just ignore log event long gtidLenth = buffer.getUint32();
mariaGTIDSet = new MariaGTIDSet();
for (int i = 0; i < gtidLenth; i++) {
long domainId = buffer.getUint32();
long serverId = buffer.getUint32();
long sequence = buffer.getUlong64().longValue();
mariaGTIDSet.add(new MariaGtid(domainId, serverId, sequence));
}
} }
public String getGtidStr() {
return mariaGTIDSet.toString();
}
} }

View File

@@ -1,6 +1,8 @@
package com.taobao.tddl.dbsync.binlog.event.mariadb; package com.taobao.tddl.dbsync.binlog.event.mariadb;
import com.alibaba.otter.canal.parse.driver.mysql.packets.MariaGtid;
import com.taobao.tddl.dbsync.binlog.LogBuffer; import com.taobao.tddl.dbsync.binlog.LogBuffer;
import com.taobao.tddl.dbsync.binlog.LogEvent;
import com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent; import com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;
import com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent; import com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent;
import com.taobao.tddl.dbsync.binlog.event.LogHeader; import com.taobao.tddl.dbsync.binlog.event.LogHeader;
@@ -11,9 +13,9 @@ import com.taobao.tddl.dbsync.binlog.event.LogHeader;
* @author jianghang 2014-1-20 下午4:49:10 * @author jianghang 2014-1-20 下午4:49:10
* @since 1.0.17 * @since 1.0.17
*/ */
public class MariaGtidLogEvent extends IgnorableLogEvent { public class MariaGtidLogEvent extends LogEvent {
private long gtid; private MariaGtid mariaGtid;
/** /**
* <pre> * <pre>
@@ -30,13 +32,14 @@ public class MariaGtidLogEvent extends IgnorableLogEvent {
*/ */
public MariaGtidLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){ public MariaGtidLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){
super(header, buffer, descriptionEvent); super(header);
gtid = buffer.getUlong64().longValue(); long sequence = buffer.getUlong64().longValue();
// do nothing , just ignore log event long domainId = buffer.getUint32();
long serverId = header.getServerId();
mariaGtid = new MariaGtid(domainId, serverId, sequence);
} }
public long getGtid() { public String getGtidStr() {
return gtid; return mariaGtid.toString();
} }
} }

View File

@@ -1,6 +1,5 @@
package com.taobao.tddl.dbsync; package com.taobao.tddl.dbsync;
import java.io.IOException;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.Statement; import java.sql.Statement;
@@ -12,8 +11,7 @@ import com.taobao.tddl.dbsync.binlog.LogEvent;
public class FetcherPerformanceTest { public class FetcherPerformanceTest {
public static void main(String args[]) { public static void main(String args[]) {
DirectLogFetcher fetcher = new DirectLogFetcher(); try (DirectLogFetcher fetcher = new DirectLogFetcher()) {
try {
Class.forName("com.mysql.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306", "root", "hello"); Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306", "root", "hello");
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
@@ -40,11 +38,6 @@ public class FetcherPerformanceTest {
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally {
try {
fetcher.close();
} catch (IOException e) {
}
} }
} }
} }

View File

@@ -30,7 +30,7 @@ public class LogHeaderTest {
final LogHeader objectUnderTest = new LogHeader(type); final LogHeader objectUnderTest = new LogHeader(type);
// Assert side effects // Assert side effects
final HashMap<String, String> hashMap = new HashMap<String, String>(); final HashMap<String, String> hashMap = new HashMap<>();
Assert.assertEquals(hashMap, objectUnderTest.gtidMap); Assert.assertEquals(hashMap, objectUnderTest.gtidMap);
} }

Some files were not shown because too many files have changed in this diff Show More