mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
Compare commits
50 Commits
canal-1.1.
...
canal-1.1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64862503ba | ||
|
|
f9e0dc7daa | ||
|
|
0c399509a9 | ||
|
|
a09cd9adb5 | ||
|
|
1369418c6a | ||
|
|
75174a63af | ||
|
|
17f4ee13e7 | ||
|
|
f0417502f8 | ||
|
|
a7720b51e4 | ||
|
|
21904ef1dc | ||
|
|
94425223bd | ||
|
|
7857df9701 | ||
|
|
64ea4ff222 | ||
|
|
85df89f777 | ||
|
|
a0f8e182ec | ||
|
|
33721d0394 | ||
|
|
91bddfeed6 | ||
|
|
25feab4af8 | ||
|
|
f66baeabf1 | ||
|
|
b1dc3821ea | ||
|
|
f5f79104eb | ||
|
|
e8d138d3bd | ||
|
|
32d9e58915 | ||
|
|
58448e559d | ||
|
|
fede3b3d1d | ||
|
|
5d8ec31bc4 | ||
|
|
82b18ebe62 | ||
|
|
66408782b0 | ||
|
|
846c8870ae | ||
|
|
8cfb07f07e | ||
|
|
d741425895 | ||
|
|
20add85ff6 | ||
|
|
a5c09c521e | ||
|
|
c94276b1ac | ||
|
|
272d575c78 | ||
|
|
693f8d501a | ||
|
|
bb1b6b9862 | ||
|
|
8ed82caaef | ||
|
|
de1dd70609 | ||
|
|
09429c241f | ||
|
|
9a332940d7 | ||
|
|
362974b1c2 | ||
|
|
435db30b7b | ||
|
|
e7de8289cd | ||
|
|
5065fea963 | ||
|
|
6989eb3d2b | ||
|
|
df24596092 | ||
|
|
43c23ffb97 | ||
|
|
e7658879bc | ||
|
|
df60eda679 |
@@ -90,10 +90,13 @@ canal 作为 MySQL binlog 增量获取和解析工具,可将变更记录投递
|
||||
|
||||
- 参考文档: [Canal Kafka/RocketMQ QuickStart](https://github.com/alibaba/canal/wiki/Canal-Kafka-RocketMQ-QuickStart)
|
||||
|
||||
## 相关开源
|
||||
## 相关开源&产品
|
||||
|
||||
- [canal 消费端开源项目: Otter](http://github.com/alibaba/otter)
|
||||
- [阿里巴巴去 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)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.admin</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.admin</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>canal.admin-web</artifactId>
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
#!/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
|
||||
|
||||
@@ -12,6 +12,6 @@ public class Threads {
|
||||
pool,
|
||||
0L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<Runnable>(pool * 20),
|
||||
new ArrayBlockingQueue<>(pool * 20),
|
||||
DaemonThreadFactory.daemonThreadFactory);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,9 @@ public class WebConfig implements WebMvcConfigurer {
|
||||
}
|
||||
})
|
||||
.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/logout")
|
||||
.excludePathPatterns("/api/**/user/info");
|
||||
|
||||
@@ -108,9 +108,7 @@ public class SimpleAdminConnector implements AdminConnector {
|
||||
}
|
||||
|
||||
connected = true;
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException(e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
} catch (IOException | NoSuchAlgorithmException e) {
|
||||
throw new ServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,14 +46,15 @@ public class PollingConfigController {
|
||||
public BaseModel<CanalConfig> canalConfigPoll(@RequestHeader String user, @RequestHeader String passwd,
|
||||
@RequestParam String ip, @RequestParam Integer port,
|
||||
@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)) {
|
||||
throw new RuntimeException("auth :" + user + " is failed");
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(md5) && register) {
|
||||
// do something
|
||||
pollingConfigService.autoRegister(ip, port, cluster);
|
||||
pollingConfigService.autoRegister(ip, port, cluster, StringUtils.trimToNull(name));
|
||||
}
|
||||
|
||||
CanalConfig canalConfig = pollingConfigService.getChangedConfig(ip, port, md5);
|
||||
|
||||
@@ -9,7 +9,7 @@ public class Pager<T> implements Serializable {
|
||||
private static final long serialVersionUID = -986577815091763517L;
|
||||
|
||||
private Long count = 0L;
|
||||
private List<T> items = new ArrayList<T>();
|
||||
private List<T> items = new ArrayList<>();
|
||||
private Integer page = 1;
|
||||
private Integer size = 20;
|
||||
private Long offset = 0L;
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.alibaba.otter.canal.admin.service.impl;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
@@ -28,11 +29,11 @@ public class PollingConfigServiceImpl implements PollingConfigService {
|
||||
@Autowired
|
||||
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();
|
||||
if (server == null) {
|
||||
server = new NodeServer();
|
||||
server.setName(ip);
|
||||
server.setName(Optional.ofNullable(name).orElse(ip));
|
||||
server.setIp(ip);
|
||||
server.setAdminPort(adminPort);
|
||||
server.setTcpPort(adminPort + 1);
|
||||
|
||||
@@ -16,6 +16,10 @@ canal.metrics.pull.port = 11112
|
||||
canal.admin.port = 11110
|
||||
canal.admin.user = admin
|
||||
canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441
|
||||
# admin auto register
|
||||
#canal.admin.register.auto = true
|
||||
#canal.admin.register.cluster =
|
||||
#canal.admin.register.name =
|
||||
|
||||
canal.zkServers =
|
||||
# flush data to zk
|
||||
@@ -60,6 +64,9 @@ canal.instance.filter.query.ddl = false
|
||||
canal.instance.filter.table.error = false
|
||||
canal.instance.filter.rows = 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
|
||||
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
|
||||
canal.auto.scan = true
|
||||
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/mysql-tsdb.xml
|
||||
@@ -151,6 +161,7 @@ rocketmq.namespace =
|
||||
rocketmq.namesrv.addr = 127.0.0.1:9876
|
||||
rocketmq.retry.times.when.send.failed = 0
|
||||
rocketmq.vip.channel.enabled = false
|
||||
rocketmq.tag =
|
||||
|
||||
##################################################
|
||||
######### RabbitMQ #############
|
||||
@@ -159,4 +170,5 @@ rabbitmq.host =
|
||||
rabbitmq.virtual.host =
|
||||
rabbitmq.exchange =
|
||||
rabbitmq.username =
|
||||
rabbitmq.password =
|
||||
rabbitmq.password =
|
||||
rabbitmq.deliveryMode =
|
||||
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal.admin</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>canal admin module for otter ${project.version}</name>
|
||||
<modules>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -140,7 +140,7 @@ public class YmlConfigBinder {
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(propertySource);
|
||||
|
||||
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(target);
|
||||
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<>(target);
|
||||
factory.setPropertySources(propertySources);
|
||||
factory.setIgnoreInvalidFields(true);
|
||||
factory.setIgnoreUnknownFields(true);
|
||||
|
||||
@@ -25,7 +25,7 @@ class DefaultPropertyNamePatternsMatcher implements PropertyNamePatternsMatcher
|
||||
}
|
||||
|
||||
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){
|
||||
@@ -70,8 +70,8 @@ class DefaultPropertyNamePatternsMatcher implements PropertyNamePatternsMatcher
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < match.length; i++) {
|
||||
if (match[i]) {
|
||||
for (boolean b : match) {
|
||||
if (b) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>, Applic
|
||||
}
|
||||
|
||||
private Set<String> getNames(Iterable<String> prefixes) {
|
||||
Set<String> names = new LinkedHashSet<String>();
|
||||
Set<String> names = new LinkedHashSet<>();
|
||||
if (this.target != null) {
|
||||
PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(this.target.getClass());
|
||||
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't do a complete filter since we need to trigger the
|
||||
// unknown fields check
|
||||
Set<String> relaxedNames = new HashSet<String>();
|
||||
Set<String> relaxedNames = new HashSet<>();
|
||||
for (String relaxedTargetName : relaxedTargetNames) {
|
||||
relaxedNames.add(relaxedTargetName);
|
||||
}
|
||||
|
||||
@@ -9,23 +9,9 @@ package com.alibaba.otter.canal.client.adapter.config.bind;
|
||||
*/
|
||||
interface PropertyNamePatternsMatcher {
|
||||
|
||||
PropertyNamePatternsMatcher ALL = new PropertyNamePatternsMatcher() {
|
||||
PropertyNamePatternsMatcher ALL = propertyName -> true;
|
||||
|
||||
@Override
|
||||
public boolean matches(String propertyName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
PropertyNamePatternsMatcher NONE = new PropertyNamePatternsMatcher() {
|
||||
|
||||
@Override
|
||||
public boolean matches(String propertyName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
PropertyNamePatternsMatcher NONE = propertyName -> false;
|
||||
|
||||
/**
|
||||
* Return {@code true} of the property name matches.
|
||||
|
||||
@@ -37,9 +37,9 @@ public class PropertySourcesPropertyValues implements PropertyValues {
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
private static final Set<Class<?>> EXCLUDED_EDITORS;
|
||||
|
||||
static {
|
||||
Set<Class<?>> excluded = new HashSet<Class<?>>();
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(FileEditor.class);
|
||||
EXCLUDED_EDITORS = Collections.unmodifiableSet(excluded);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
|
||||
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.
|
||||
@@ -89,7 +89,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
* @param aliases a map of property name to 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);
|
||||
wrapper.setConversionService(new RelaxedConversionService(getConversionService()));
|
||||
wrapper.setAutoGrowNestedPaths(true);
|
||||
List<PropertyValue> sortedValues = new ArrayList<PropertyValue>();
|
||||
Set<String> modifiedNames = new HashSet<String>();
|
||||
List<PropertyValue> sortedValues = new ArrayList<>();
|
||||
Set<String> modifiedNames = new HashSet<>();
|
||||
List<String> sortedNames = getSortedPropertyNames(propertyValues);
|
||||
for (String name : sortedNames) {
|
||||
PropertyValue propertyValue = propertyValues.getPropertyValue(name);
|
||||
@@ -143,7 +143,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
}
|
||||
|
||||
private List<String> getSortedPropertyNames(MutablePropertyValues propertyValues) {
|
||||
List<String> names = new LinkedList<String>();
|
||||
List<String> names = new LinkedList<>();
|
||||
for (PropertyValue propertyValue : propertyValues.getPropertyValueList()) {
|
||||
names.add(propertyValue.getName());
|
||||
}
|
||||
@@ -161,7 +161,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
* @param names the names to sort
|
||||
*/
|
||||
private void sortPropertyNames(List<String> names) {
|
||||
for (String name : new ArrayList<String>(names)) {
|
||||
for (String name : new ArrayList<>(names)) {
|
||||
int propertyIndex = names.indexOf(name);
|
||||
RelaxedDataBinder.BeanPath path = new RelaxedDataBinder.BeanPath(name);
|
||||
for (String prefix : path.prefixes()) {
|
||||
@@ -319,7 +319,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
}
|
||||
Object extend = new LinkedHashMap<String, Object>();
|
||||
if (!elementDescriptor.isMap() && path.isArrayIndex(index)) {
|
||||
extend = new ArrayList<Object>();
|
||||
extend = new ArrayList<>();
|
||||
}
|
||||
wrapper.setPropertyValue(path.prefix(index + 1), extend);
|
||||
}
|
||||
@@ -347,7 +347,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
}
|
||||
Object extend = new LinkedHashMap<String, Object>();
|
||||
if (descriptor.isCollection()) {
|
||||
extend = new ArrayList<Object>();
|
||||
extend = new ArrayList<>();
|
||||
}
|
||||
if (descriptor.getType().equals(Object.class) && path.isLastNode(index)) {
|
||||
extend = BLANK;
|
||||
@@ -411,7 +411,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
if (aliases == null) {
|
||||
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.addAll(aliases);
|
||||
return nameAndAliases;
|
||||
@@ -473,7 +473,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
}
|
||||
|
||||
public List<String> prefixes() {
|
||||
List<String> prefixes = new ArrayList<String>();
|
||||
List<String> prefixes = new ArrayList<>();
|
||||
for (int index = 1; index < this.nodes.size(); index++) {
|
||||
prefixes.add(prefix(index));
|
||||
}
|
||||
@@ -485,7 +485,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
}
|
||||
|
||||
private List<PathNode> splitPath(String path) {
|
||||
List<PathNode> nodes = new ArrayList<PathNode>();
|
||||
List<PathNode> nodes = new ArrayList<>();
|
||||
String current = extractIndexedPaths(path, nodes);
|
||||
for (String name : StringUtils.delimitedListToStringArray(current, ".")) {
|
||||
if (StringUtils.hasText(name)) {
|
||||
@@ -518,7 +518,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
}
|
||||
|
||||
public void collapseKeys(int index) {
|
||||
List<PathNode> revised = new ArrayList<PathNode>();
|
||||
List<PathNode> revised = new ArrayList<>();
|
||||
for (int i = 0; i < index; 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;
|
||||
|
||||
static {
|
||||
Set<String> names = new HashSet<String>();
|
||||
Set<String> names = new HashSet<>();
|
||||
names.add(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
|
||||
names.add(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);
|
||||
BENIGN_PROPERTY_SOURCE_NAMES = Collections.unmodifiableSet(names);
|
||||
|
||||
@@ -24,7 +24,7 @@ public final class RelaxedNames implements Iterable<String> {
|
||||
|
||||
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.
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
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}.
|
||||
@@ -56,7 +56,7 @@ public class CompositePropertySource extends EnumerablePropertySource<Object> {
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
Set<String> names = new LinkedHashSet<String>();
|
||||
Set<String> names = new LinkedHashSet<>();
|
||||
for (PropertySource<?> propertySource : this.propertySources) {
|
||||
if (!(propertySource instanceof EnumerablePropertySource)) {
|
||||
throw new IllegalStateException(
|
||||
@@ -83,7 +83,7 @@ public class CompositePropertySource extends EnumerablePropertySource<Object> {
|
||||
* @since 4.1
|
||||
*/
|
||||
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.add(propertySource);
|
||||
this.propertySources.addAll(existing);
|
||||
|
||||
@@ -28,7 +28,7 @@ public class MutablePropertySources implements PropertySources {
|
||||
|
||||
private final Log logger;
|
||||
|
||||
private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();
|
||||
private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();
|
||||
|
||||
/**
|
||||
* Create a new {@link MutablePropertySources}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class SpringProfileDocumentMatcher implements YamlProcessor.DocumentMatch
|
||||
}
|
||||
|
||||
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);
|
||||
this.activeProfiles = set.toArray(new String[set.size()]);
|
||||
}
|
||||
@@ -67,14 +67,14 @@ public class SpringProfileDocumentMatcher implements YamlProcessor.DocumentMatch
|
||||
|
||||
private ProfilesMatcher getProfilesMatcher() {
|
||||
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) {
|
||||
if (CollectionUtils.isEmpty(profiles)) {
|
||||
return null;
|
||||
}
|
||||
Set<String> extractedProfiles = new HashSet<String>();
|
||||
Set<String> extractedProfiles = new HashSet<>();
|
||||
for (String candidate : profiles) {
|
||||
ProfileType candidateType = ProfileType.POSITIVE;
|
||||
if (candidate.startsWith("!")) {
|
||||
@@ -167,7 +167,7 @@ public class SpringProfileDocumentMatcher implements YamlProcessor.DocumentMatch
|
||||
*/
|
||||
static class SpringProperties {
|
||||
|
||||
private List<String> profiles = new ArrayList<String>();
|
||||
private List<String> profiles = new ArrayList<>();
|
||||
|
||||
public List<String> getProfiles() {
|
||||
return this.profiles;
|
||||
|
||||
@@ -130,8 +130,7 @@ public abstract class YamlProcessor {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading from YAML: " + resource);
|
||||
}
|
||||
Reader reader = new UnicodeReader(resource.getInputStream());
|
||||
try {
|
||||
try (Reader reader = new UnicodeReader(resource.getInputStream())) {
|
||||
for (Object object : yaml.loadAll(reader)) {
|
||||
if (object != null && process(asMap(object), callback)) {
|
||||
count++;
|
||||
@@ -142,10 +141,8 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
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) {
|
||||
handleProcessError(resource, ex);
|
||||
@@ -166,7 +163,7 @@ public abstract class YamlProcessor {
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> asMap(Object object) {
|
||||
// YAML can have numbers as keys
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
if (!(object instanceof Map)) {
|
||||
// A document can be a text literal
|
||||
result.put("document", object);
|
||||
@@ -249,7 +246,7 @@ public abstract class YamlProcessor {
|
||||
* @since 4.1.3
|
||||
*/
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.alibaba.otter.canal.client.adapter.config.common;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -72,14 +71,8 @@ public class YamlPropertySourceLoader implements PropertySourceLoader {
|
||||
}
|
||||
|
||||
public Map<String, Object> process() {
|
||||
final Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||
process(new MatchCallback() {
|
||||
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
result.putAll(getFlattenedMap(map));
|
||||
}
|
||||
});
|
||||
final Map<String, Object> result = new LinkedHashMap<>();
|
||||
process((properties, map) -> result.putAll(getFlattenedMap(map)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
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)
|
||||
String dir = File.separator + this.getJarDirectoryPath() + File.separator + "plugin";
|
||||
@@ -317,10 +318,8 @@ public class ExtensionLoader<T> {
|
||||
while (urls.hasMoreElements()) {
|
||||
URL url = urls.nextElement();
|
||||
try {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
|
||||
String line = null;
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
final int ci = line.indexOf('#');
|
||||
if (ci >= 0) line = line.substring(0, ci);
|
||||
@@ -340,10 +339,10 @@ public class ExtensionLoader<T> {
|
||||
// classLoader);
|
||||
if (!type.isAssignableFrom(clazz)) {
|
||||
throw new IllegalStateException(
|
||||
"Error when load extension class(interface: " + type
|
||||
+ ", class line: " + clazz.getName()
|
||||
+ "), class " + clazz.getName()
|
||||
+ "is not subtype of interface.");
|
||||
"Error when load extension class(interface: " + type
|
||||
+ ", class line: " + clazz.getName()
|
||||
+ "), class " + clazz.getName()
|
||||
+ "is not subtype of interface.");
|
||||
} else {
|
||||
try {
|
||||
clazz.getConstructor(type);
|
||||
@@ -361,10 +360,10 @@ public class ExtensionLoader<T> {
|
||||
} else if (c != clazz) {
|
||||
cachedNames.remove(clazz);
|
||||
throw new IllegalStateException(
|
||||
"Duplicate extension " + type.getName() + " name "
|
||||
+ n + " on "
|
||||
+ c.getName() + " and "
|
||||
+ clazz.getName());
|
||||
"Duplicate extension " + type.getName() + " name "
|
||||
+ n + " on "
|
||||
+ c.getName() + " and "
|
||||
+ clazz.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,19 +372,15 @@ public class ExtensionLoader<T> {
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
IllegalStateException e = new IllegalStateException(
|
||||
"Failed to load extension class(interface: " + type + ", class line: "
|
||||
+ line + ") in " + url
|
||||
+ ", cause: "
|
||||
+ t.getMessage(),
|
||||
t);
|
||||
"Failed to load extension class(interface: " + type + ", class line: "
|
||||
+ line + ") in " + url
|
||||
+ ", cause: "
|
||||
+ t.getMessage(),
|
||||
t);
|
||||
exceptions.put(line, e);
|
||||
}
|
||||
}
|
||||
} // end of while read lines
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.error("Exception when load extension class(interface: " + type + ", class file: " + url
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.util.*;
|
||||
|
||||
import com.alibaba.otter.canal.connector.core.consumer.CommonMessage;
|
||||
import com.alibaba.otter.canal.protocol.CanalEntry;
|
||||
import com.alibaba.otter.canal.protocol.FlatMessage;
|
||||
import com.alibaba.otter.canal.protocol.Message;
|
||||
|
||||
/**
|
||||
@@ -20,7 +19,7 @@ public class MessageUtil {
|
||||
return null;
|
||||
}
|
||||
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) {
|
||||
if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN
|
||||
|| entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {
|
||||
@@ -136,7 +135,7 @@ public class MessageUtil {
|
||||
if (commonMessages == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<Dml> dmls = new ArrayList<Dml>(commonMessages.size());
|
||||
List<Dml> dmls = new ArrayList<>(commonMessages.size());
|
||||
for (CommonMessage commonMessage : commonMessages) {
|
||||
Dml dml = flatMessage2Dml(destination, groupId, commonMessage);
|
||||
if (dml != null) {
|
||||
|
||||
@@ -7,7 +7,8 @@ import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class URLClassExtensionLoader extends URLClassLoader {
|
||||
public URLClassExtensionLoader(URL[] urls) {
|
||||
|
||||
public URLClassExtensionLoader(URL[] urls){
|
||||
super(urls);
|
||||
}
|
||||
|
||||
@@ -18,9 +19,9 @@ public class URLClassExtensionLoader extends URLClassLoader {
|
||||
return c;
|
||||
}
|
||||
|
||||
if (name.startsWith("java.") || name.startsWith("org.slf4j.")
|
||||
|| name.startsWith("org.apache.logging")
|
||||
|| name.startsWith("org.apache.commons.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.hadoop."))
|
||||
// {
|
||||
c = super.loadClass(name);
|
||||
|
||||
@@ -1,24 +1,13 @@
|
||||
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.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.Timeout;
|
||||
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 java.lang.reflect.Array;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
public class JdbcTypeUtilTest {
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@ 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.Util;
|
||||
import com.diffblue.deeptestutils.mock.DTUMemberMatcher;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.junit.Assert;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -2,7 +2,10 @@ package com.alibaba.otter.canal.client.adapter.es6x.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
@@ -78,14 +81,7 @@ public class ESConnection {
|
||||
Integer.parseInt(host.substring(i + 1))));
|
||||
}
|
||||
} else {
|
||||
HttpHost[] httpHosts = new HttpHost[hosts.length];
|
||||
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;
|
||||
}
|
||||
HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);
|
||||
RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);
|
||||
String nameAndPwd = properties.get("security.auth");
|
||||
if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(":")) {
|
||||
@@ -507,4 +503,17 @@ public class ESConnection {
|
||||
public void setRestHighLevelClient(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -2,7 +2,10 @@ package com.alibaba.otter.canal.client.adapter.es7x.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
@@ -77,14 +80,7 @@ public class ESConnection {
|
||||
Integer.parseInt(host.substring(i + 1))));
|
||||
}
|
||||
} else {
|
||||
HttpHost[] httpHosts = new HttpHost[hosts.length];
|
||||
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;
|
||||
}
|
||||
HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);
|
||||
RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);
|
||||
String nameAndPwd = properties.get("security.auth");
|
||||
if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(":")) {
|
||||
@@ -501,4 +497,17 @@ public class ESConnection {
|
||||
public void setRestHighLevelClient(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -22,8 +20,8 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastsql</groupId>
|
||||
<artifactId>fastsql</artifactId>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
package com.alibaba.otter.canal.client.adapter.es.core.config;
|
||||
|
||||
import static com.alibaba.fastsql.sql.ast.expr.SQLBinaryOperator.BooleanAnd;
|
||||
import static com.alibaba.fastsql.sql.ast.expr.SQLBinaryOperator.Equality;
|
||||
import static com.alibaba.druid.sql.ast.expr.SQLBinaryOperator.BooleanAnd;
|
||||
import static com.alibaba.druid.sql.ast.expr.SQLBinaryOperator.Equality;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.alibaba.fastsql.sql.SQLUtils;
|
||||
import com.alibaba.fastsql.sql.ast.SQLExpr;
|
||||
import com.alibaba.fastsql.sql.ast.expr.SQLBinaryOpExpr;
|
||||
import com.alibaba.fastsql.sql.ast.expr.SQLCaseExpr;
|
||||
import com.alibaba.fastsql.sql.ast.expr.SQLCharExpr;
|
||||
import com.alibaba.fastsql.sql.ast.expr.SQLIdentifierExpr;
|
||||
import com.alibaba.fastsql.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.fastsql.sql.ast.expr.SQLPropertyExpr;
|
||||
import com.alibaba.fastsql.sql.ast.statement.SQLExprTableSource;
|
||||
import com.alibaba.fastsql.sql.ast.statement.SQLJoinTableSource;
|
||||
import com.alibaba.fastsql.sql.ast.statement.SQLSelectGroupByClause;
|
||||
import com.alibaba.fastsql.sql.ast.statement.SQLSelectItem;
|
||||
import com.alibaba.fastsql.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.fastsql.sql.ast.statement.SQLSubqueryTableSource;
|
||||
import com.alibaba.fastsql.sql.ast.statement.SQLTableSource;
|
||||
import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
|
||||
import com.alibaba.fastsql.sql.dialect.mysql.parser.MySqlStatementParser;
|
||||
import com.alibaba.fastsql.sql.parser.ParserException;
|
||||
import com.alibaba.fastsql.sql.parser.SQLStatementParser;
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLCaseExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
|
||||
import com.alibaba.druid.sql.parser.ParserException;
|
||||
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.FieldItem;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.RelationFieldsPair;
|
||||
@@ -230,8 +230,7 @@ public class SqlParser {
|
||||
}
|
||||
FieldItem rightFieldItem = new FieldItem();
|
||||
visitColumn(sqlBinaryOpExpr.getRight(), rightFieldItem);
|
||||
if (rightFieldItem.getColumnItems().size() != 1 || rightFieldItem.isMethod()
|
||||
|| rightFieldItem.isBinaryOp()) {
|
||||
if (rightFieldItem.getColumnItems().size() != 1 || rightFieldItem.isMethod() || rightFieldItem.isBinaryOp()) {
|
||||
throw new UnsupportedOperationException("Unsupported for complex of on-condition");
|
||||
}
|
||||
tableItem.getRelationFields().add(new RelationFieldsPair(leftFieldItem, rightFieldItem));
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
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.ESMapping;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem;
|
||||
|
||||
@@ -63,172 +63,187 @@ public class ESSyncUtil {
|
||||
return val;
|
||||
}
|
||||
Object res = null;
|
||||
if ("integer".equals(esType)) {
|
||||
if (val instanceof Number) {
|
||||
res = ((Number) val).intValue();
|
||||
} else {
|
||||
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");
|
||||
switch (esType) {
|
||||
case "integer":
|
||||
if (val instanceof Number) {
|
||||
res = ((Number) val).intValue();
|
||||
} else {
|
||||
res = dateTime.toString("HH:mm:ss");
|
||||
res = Integer.parseInt(val.toString());
|
||||
}
|
||||
} else if (val instanceof java.sql.Timestamp) {
|
||||
DateTime dateTime = new DateTime(((java.sql.Timestamp) val).getTime());
|
||||
if (dateTime.getMillisOfSecond() != 0) {
|
||||
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone);
|
||||
break;
|
||||
case "long":
|
||||
if (val instanceof Number) {
|
||||
res = ((Number) val).longValue();
|
||||
} 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) {
|
||||
DateTime dateTime;
|
||||
if (val instanceof java.sql.Date) {
|
||||
dateTime = new DateTime(((java.sql.Date) val).getTime());
|
||||
break;
|
||||
case "short":
|
||||
if (val instanceof Number) {
|
||||
res = ((Number) val).shortValue();
|
||||
} else {
|
||||
dateTime = new DateTime(((Date) val).getTime());
|
||||
res = Short.parseShort(val.toString());
|
||||
}
|
||||
if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0
|
||||
&& dateTime.getMillisOfSecond() == 0) {
|
||||
res = dateTime.toString("yyyy-MM-dd");
|
||||
break;
|
||||
case "byte":
|
||||
if (val instanceof Number) {
|
||||
res = ((Number) val).byteValue();
|
||||
} 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) {
|
||||
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 Long) {
|
||||
DateTime dateTime = new DateTime(((Long) val).longValue());
|
||||
if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0
|
||||
&& dateTime.getMillisOfSecond() == 0) {
|
||||
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);
|
||||
} else if (val instanceof java.sql.Date || val instanceof Date) {
|
||||
DateTime dateTime;
|
||||
if (val instanceof java.sql.Date) {
|
||||
dateTime = new DateTime(((java.sql.Date) val).getTime());
|
||||
} else {
|
||||
dateTime = new DateTime(((Date) val).getTime());
|
||||
}
|
||||
if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0
|
||||
&& dateTime.getMillisOfSecond() == 0) {
|
||||
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 (v.length() == 10 && v.charAt(4) == '-' && v.charAt(7) == '-') {
|
||||
Date date = Util.parseDate(v);
|
||||
if (date != null) {
|
||||
DateTime dateTime = new DateTime(date);
|
||||
} else if (val instanceof Long) {
|
||||
DateTime dateTime = new DateTime(((Long) val).longValue());
|
||||
if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0
|
||||
&& dateTime.getMillisOfSecond() == 0) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ("binary".equals(esType)) {
|
||||
if (val instanceof byte[]) {
|
||||
Base64 base64 = new Base64();
|
||||
res = base64.encodeAsString((byte[]) val);
|
||||
} else if (val instanceof Blob) {
|
||||
byte[] b = blobToBytes((Blob) val);
|
||||
Base64 base64 = new Base64();
|
||||
res = base64.encodeAsString(b);
|
||||
} else if (val instanceof String) {
|
||||
// 对应canal中的单字节编码
|
||||
byte[] b = ((String) val).getBytes(StandardCharsets.ISO_8859_1);
|
||||
Base64 base64 = new Base64();
|
||||
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 = "-";
|
||||
}
|
||||
break;
|
||||
case "binary":
|
||||
if (val instanceof byte[]) {
|
||||
Base64 base64 = new Base64();
|
||||
res = base64.encodeAsString((byte[]) val);
|
||||
} else if (val instanceof Blob) {
|
||||
byte[] b = blobToBytes((Blob) val);
|
||||
Base64 base64 = new Base64();
|
||||
res = base64.encodeAsString(b);
|
||||
} else if (val instanceof String) {
|
||||
// 对应canal中的单字节编码
|
||||
byte[] b = ((String) val).getBytes(StandardCharsets.ISO_8859_1);
|
||||
Base64 base64 = new Base64();
|
||||
res = base64.encodeAsString(b);
|
||||
}
|
||||
String[] values = value.split(separator);
|
||||
return Arrays.asList(values);
|
||||
}
|
||||
} else if ("object".equals(esType)) {
|
||||
if ("".equals(val.toString().trim())) {
|
||||
res = new HashMap<>();
|
||||
} else {
|
||||
res = JSON.parseObject(val.toString(), Map.class);
|
||||
}
|
||||
} else {
|
||||
// 其他类全以字符串处理
|
||||
res = val.toString();
|
||||
break;
|
||||
case "geo_point":
|
||||
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;
|
||||
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;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -20,7 +20,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.hbase</groupId>
|
||||
<artifactId>hbase-client</artifactId>
|
||||
<artifactId>hbase-shaded-client</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package com.alibaba.otter.canal.client.adapter.hbase.monitor;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import com.alibaba.otter.canal.client.adapter.config.YmlConfigBinder;
|
||||
import com.alibaba.otter.canal.client.adapter.hbase.HbaseAdapter;
|
||||
import com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig;
|
||||
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.monitor.FileAlterationListenerAdaptor;
|
||||
@@ -13,11 +14,10 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.otter.canal.client.adapter.config.YmlConfigBinder;
|
||||
import com.alibaba.otter.canal.client.adapter.hbase.HbaseAdapter;
|
||||
import com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;
|
||||
import com.alibaba.otter.canal.client.adapter.support.Util;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class HbaseConfigMonitor {
|
||||
|
||||
@@ -125,8 +125,8 @@ public class HbaseConfigMonitor {
|
||||
private void addConfigToCache(File file, MappingConfig config) {
|
||||
hbaseAdapter.getHbaseMapping().put(file.getName(), config);
|
||||
Map<String, MappingConfig> configMap = hbaseAdapter.getMappingConfigCache()
|
||||
.computeIfAbsent(StringUtils.trimToEmpty(config.getDestination()) + "."
|
||||
+ config.getHbaseMapping().getDatabase() + "." + config.getHbaseMapping().getTable(),
|
||||
.computeIfAbsent(StringUtils.trimToEmpty(config.getDestination()) + "_"
|
||||
+ config.getHbaseMapping().getDatabase() + "-" + config.getHbaseMapping().getTable(),
|
||||
k1 -> new HashMap<>());
|
||||
configMap.put(file.getName(), config);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -73,7 +71,7 @@
|
||||
<tasks>
|
||||
<copy todir="${project.basedir}/../launcher/target/classes/kudu" overwrite="true">
|
||||
<fileset dir="${project.basedir}/target/classes/kudu" erroronmissingdir="true">
|
||||
<include name="*.yml"/>
|
||||
<include name="*.yml" />
|
||||
</fileset>
|
||||
</copy>
|
||||
</tasks>
|
||||
|
||||
@@ -88,45 +88,40 @@ public class KuduEtlService extends AbstractEtlService {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : columnsMap.entrySet()) {
|
||||
String mysqlColumnName = entry.getKey();// mysql字段名
|
||||
String kuduColumnName = entry.getValue();// kudu字段名
|
||||
if (kuduColumnName == null) {
|
||||
kuduColumnName = mysqlColumnName;
|
||||
}
|
||||
Object value = rs.getObject(kuduColumnName);
|
||||
if (value != null) {
|
||||
data.put(kuduColumnName, value);
|
||||
} else {
|
||||
data.put(kuduColumnName, null);
|
||||
}
|
||||
}
|
||||
dataList.add(data);
|
||||
idx++;
|
||||
impCount.incrementAndGet();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("successful import count:" + impCount.get());
|
||||
}
|
||||
if (idx % kuduMapping.getCommitBatch() == 0) {
|
||||
kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);
|
||||
dataList.clear();
|
||||
}
|
||||
}
|
||||
if (!dataList.isEmpty()) {
|
||||
kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);
|
||||
}
|
||||
return true;
|
||||
String kuduColumnName = entry.getValue();// kudu字段名
|
||||
if (kuduColumnName == null) {
|
||||
kuduColumnName = mysqlColumnName;
|
||||
}
|
||||
Object value = rs.getObject(kuduColumnName);
|
||||
if (value != null) {
|
||||
data.put(kuduColumnName, value);
|
||||
} else {
|
||||
data.put(kuduColumnName, null);
|
||||
}
|
||||
}
|
||||
dataList.add(data);
|
||||
idx++;
|
||||
impCount.incrementAndGet();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("successful import count:" + impCount.get());
|
||||
}
|
||||
if (idx % kuduMapping.getCommitBatch() == 0) {
|
||||
kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);
|
||||
dataList.clear();
|
||||
}
|
||||
}
|
||||
if (!dataList.isEmpty()) {
|
||||
kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);
|
||||
}
|
||||
return true;
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
logger.error(kuduMapping.getTargetTable() + " etl failed! ==>" + e.getMessage(), e);
|
||||
errMsg.add(kuduMapping.getTargetTable() + " etl failed! ==>" + e.getMessage());
|
||||
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;
|
||||
}
|
||||
} );
|
||||
} catch (SQLException | 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;
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -69,6 +69,12 @@
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.hbase</groupId>
|
||||
<artifactId>hbase-shaded-client</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- outer adapter jar with dependencies-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
#!/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
|
||||
|
||||
@@ -211,6 +211,7 @@ public class AdapterProcessor {
|
||||
canalDestination,
|
||||
System.currentTimeMillis() - begin);
|
||||
}
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (i != retry - 1) {
|
||||
canalMsgConsumer.rollback(); // 处理失败, 回滚数据
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>canal client adapter module for otter ${project.version}</name>
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.hbase</groupId>
|
||||
<artifactId>hbase-client</artifactId>
|
||||
<artifactId>hbase-shaded-client</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
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.StringReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Blob;
|
||||
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.sql.*;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
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 {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SyncUtil.class);
|
||||
|
||||
public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Map<String, Object> data) {
|
||||
return getColumnsMap(dbMapping, data.keySet());
|
||||
@@ -93,15 +88,7 @@ public class SyncUtil {
|
||||
}
|
||||
break;
|
||||
case Types.TINYINT:
|
||||
if (value instanceof Number) {
|
||||
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:
|
||||
// 向上提升一级,处理unsigned情况
|
||||
if (value instanceof Number) {
|
||||
pstmt.setShort(i, ((Number) value).shortValue());
|
||||
} else if (value instanceof String) {
|
||||
@@ -110,7 +97,7 @@ public class SyncUtil {
|
||||
pstmt.setNull(i, type);
|
||||
}
|
||||
break;
|
||||
case Types.INTEGER:
|
||||
case Types.SMALLINT:
|
||||
if (value instanceof Number) {
|
||||
pstmt.setInt(i, ((Number) value).intValue());
|
||||
} else if (value instanceof String) {
|
||||
@@ -119,7 +106,7 @@ public class SyncUtil {
|
||||
pstmt.setNull(i, type);
|
||||
}
|
||||
break;
|
||||
case Types.BIGINT:
|
||||
case Types.INTEGER:
|
||||
if (value instanceof Number) {
|
||||
pstmt.setLong(i, ((Number) value).longValue());
|
||||
} else if (value instanceof String) {
|
||||
@@ -128,6 +115,15 @@ public class SyncUtil {
|
||||
pstmt.setNull(i, type);
|
||||
}
|
||||
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.NUMERIC:
|
||||
if (value instanceof BigDecimal) {
|
||||
@@ -262,9 +258,9 @@ public class SyncUtil {
|
||||
public static String getDbTableName(MappingConfig.DbMapping dbMapping) {
|
||||
String result = "";
|
||||
if (StringUtils.isNotEmpty(dbMapping.getTargetDb())) {
|
||||
result += dbMapping.getTargetDb() + ".";
|
||||
result += ("`" + dbMapping.getTargetDb() + "`.");
|
||||
}
|
||||
result += dbMapping.getTargetTable();
|
||||
result += ("`" + dbMapping.getTargetTable() + "`");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
//wpackage com.alibaba.otter.canal.client.adapter.rdb.test;
|
||||
//
|
||||
//import com.alibaba.fastsql.sql.ast.SQLName;
|
||||
//import com.alibaba.fastsql.sql.ast.SQLStatement;
|
||||
//import com.alibaba.fastsql.sql.ast.statement.SQLCreateTableStatement;
|
||||
//import com.alibaba.fastsql.sql.ast.statement.SQLExprTableSource;
|
||||
//import com.alibaba.fastsql.sql.dialect.mysql.parser.MySqlCreateTableParser;
|
||||
//import com.alibaba.fastsql.sql.dialect.mysql.parser.MySqlStatementParser;
|
||||
//import com.alibaba.fastsql.sql.dialect.mysql.visitor.MySqlOutputVisitor;
|
||||
//import com.alibaba.fastsql.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
|
||||
//import com.alibaba.fastsql.sql.parser.SQLStatementParser;
|
||||
//import com.alibaba.druid.sql.ast.SQLName;
|
||||
//import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
//import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
|
||||
//import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
|
||||
//import com.alibaba.druid.sql.dialect.mysql.parser.MySqlCreateTableParser;
|
||||
//import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
|
||||
//import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
|
||||
//import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
|
||||
//import com.alibaba.druid.sql.parser.SQLStatementParser;
|
||||
//
|
||||
//import java.io.StringWriter;
|
||||
//
|
||||
|
||||
@@ -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>
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
|
||||
@@ -28,19 +28,14 @@ public class ClusterNodeAccessStrategy implements CanalNodeAccessStrategy {
|
||||
private IZkChildListener childListener; // 监听所有的服务器列表
|
||||
private IZkDataListener dataListener; // 监听当前的工作节点
|
||||
private ZkClientx zkClient;
|
||||
private volatile List<InetSocketAddress> currentAddress = new ArrayList<InetSocketAddress>();
|
||||
private volatile List<InetSocketAddress> currentAddress = new ArrayList<>();
|
||||
private volatile InetSocketAddress runningAddress = null;
|
||||
|
||||
public ClusterNodeAccessStrategy(String destination, ZkClientx zkClient){
|
||||
this.destination = destination;
|
||||
this.zkClient = zkClient;
|
||||
childListener = new IZkChildListener() {
|
||||
|
||||
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
|
||||
initClusters(currentChilds);
|
||||
}
|
||||
|
||||
};
|
||||
// handleChildChange
|
||||
childListener = (parentPath, currentChilds) -> initClusters(currentChilds);
|
||||
|
||||
dataListener = new IZkDataListener() {
|
||||
|
||||
@@ -80,9 +75,9 @@ public class ClusterNodeAccessStrategy implements CanalNodeAccessStrategy {
|
||||
|
||||
private void initClusters(List<String> currentChilds) {
|
||||
if (currentChilds == null || currentChilds.isEmpty()) {
|
||||
currentAddress = new ArrayList<InetSocketAddress>();
|
||||
currentAddress = new ArrayList<>();
|
||||
} else {
|
||||
List<InetSocketAddress> addresses = new ArrayList<InetSocketAddress>();
|
||||
List<InetSocketAddress> addresses = new ArrayList<>();
|
||||
for (String address : currentChilds) {
|
||||
String[] strs = StringUtils.split(address, ":");
|
||||
if (strs != null && strs.length == 2) {
|
||||
|
||||
@@ -64,7 +64,7 @@ public class SimpleCanalConnector implements CanalConnector {
|
||||
private SocketChannel channel;
|
||||
private ReadableByteChannel readableChannel;
|
||||
private WritableByteChannel writableChannel;
|
||||
private List<Compression> supportedCompressions = new ArrayList<Compression>();
|
||||
private List<Compression> supportedCompressions = new ArrayList<>();
|
||||
private ClientIdentity clientIdentity;
|
||||
private ClientRunningMonitor runningMonitor; // 运行控制
|
||||
private ZkClientx zkClientx;
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.alibaba.otter.canal.client.CanalNodeAccessStrategy;
|
||||
*/
|
||||
public class SimpleNodeAccessStrategy implements CanalNodeAccessStrategy {
|
||||
|
||||
private List<SocketAddress> nodes = new ArrayList<SocketAddress>();
|
||||
private List<SocketAddress> nodes = new ArrayList<>();
|
||||
private int index = 0;
|
||||
|
||||
public SimpleNodeAccessStrategy(List<? extends SocketAddress> nodes){
|
||||
|
||||
@@ -72,12 +72,7 @@ public class ClientRunningMonitor extends AbstractCanalLifeCycle {
|
||||
initRunning();
|
||||
} else {
|
||||
// 否则就是等待delayTime,避免因网络瞬端或者zk异常,导致出现频繁的切换操作
|
||||
delayExector.schedule(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
initRunning();
|
||||
}
|
||||
}, delayTime, TimeUnit.SECONDS);
|
||||
delayExector.schedule(() -> initRunning(), delayTime, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,11 +80,11 @@ public class KafkaCanalConnector implements CanalMQConnector {
|
||||
|
||||
connected = true;
|
||||
if (kafkaConsumer == null && !flatMessage) {
|
||||
kafkaConsumer = new KafkaConsumer<String, Message>(properties);
|
||||
kafkaConsumer = new KafkaConsumer<>(properties);
|
||||
|
||||
}
|
||||
if (kafkaConsumer2 == null && flatMessage) {
|
||||
kafkaConsumer2 = new KafkaConsumer<String, String>(properties);
|
||||
kafkaConsumer2 = new KafkaConsumer<>(properties);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,49 +59,37 @@ public class ClientRunningTest extends AbstractZkTest {
|
||||
final ClientRunningMonitor runningMonitor2 = buildClientRunning(countLatch, clientId, 2089);
|
||||
final ClientRunningMonitor runningMonitor3 = buildClientRunning(countLatch, clientId, 2090);
|
||||
final ExecutorService executor = Executors.newFixedThreadPool(3);
|
||||
executor.submit(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor1.isStart()) {
|
||||
runningMonitor1.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
runningMonitor1.stop();
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
executor.submit(() -> {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor1.isStart()) {
|
||||
runningMonitor1.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
runningMonitor1.stop();
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
executor.submit(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor2.isStart()) {
|
||||
runningMonitor2.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
runningMonitor2.stop();
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
executor.submit(() -> {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor2.isStart()) {
|
||||
runningMonitor2.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
runningMonitor2.stop();
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
executor.submit(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor3.isStart()) {
|
||||
runningMonitor3.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
runningMonitor3.stop();
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
executor.submit(() -> {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor3.isStart()) {
|
||||
runningMonitor3.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
runningMonitor3.stop();
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
sleep(30000L);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>canal.common</artifactId>
|
||||
|
||||
@@ -18,20 +18,11 @@ public class AddressUtils {
|
||||
private static final Pattern IP_PATTERN = Pattern.compile("[0-9]{1,3}(\\.[0-9]{1,3}){3,}");
|
||||
|
||||
public static boolean isAvailablePort(int port) {
|
||||
ServerSocket ss = null;
|
||||
try {
|
||||
ss = new ServerSocket(port);
|
||||
try (ServerSocket ss = new ServerSocket(port)) {
|
||||
ss.bind(null);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (ss != null) {
|
||||
try {
|
||||
ss.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
*/
|
||||
public class BooleanMutex {
|
||||
|
||||
private Sync sync;
|
||||
private final Sync sync;
|
||||
|
||||
public BooleanMutex(){
|
||||
sync = new Sync();
|
||||
@@ -47,7 +47,7 @@ public class BooleanMutex {
|
||||
/**
|
||||
* 阻塞等待Boolean为true
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* @throws InterruptedException if the current thread is interrupted
|
||||
*/
|
||||
public void get() throws InterruptedException {
|
||||
sync.innerGet();
|
||||
@@ -86,7 +86,7 @@ public class BooleanMutex {
|
||||
* Synchronization control for BooleanMutex. Uses AQS sync state to
|
||||
* represent run status
|
||||
*/
|
||||
private final class Sync extends AbstractQueuedSynchronizer {
|
||||
private static final class Sync extends AbstractQueuedSynchronizer {
|
||||
|
||||
private static final long serialVersionUID = 2559471934544126329L;
|
||||
/** State value representing that TRUE */
|
||||
|
||||
@@ -34,7 +34,7 @@ public class ExecutorTemplate {
|
||||
private volatile List<Future> futures = null;
|
||||
|
||||
public ExecutorTemplate(ThreadPoolExecutor executor){
|
||||
this.futures = Collections.synchronizedList(new ArrayList<Future>());
|
||||
this.futures = Collections.synchronizedList(new ArrayList<>());
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import com.alibaba.fastjson.TypeReference;
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.alibaba.fastjson.serializer.JSONSerializer;
|
||||
import com.alibaba.fastjson.serializer.ObjectSerializer;
|
||||
import com.alibaba.fastjson.serializer.PropertyFilter;
|
||||
import com.alibaba.fastjson.serializer.SerializeConfig;
|
||||
import com.alibaba.fastjson.serializer.SerializeWriter;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
@@ -72,20 +71,11 @@ public class JsonUtils {
|
||||
*/
|
||||
public static String marshalToString(Object obj, String... fliterFields) {
|
||||
final List<String> propertyFliters = Arrays.asList(fliterFields);
|
||||
SerializeWriter out = new SerializeWriter();
|
||||
try {
|
||||
try (SerializeWriter out = new SerializeWriter()) {
|
||||
JSONSerializer serializer = new JSONSerializer(out);
|
||||
serializer.getPropertyFilters().add(new PropertyFilter() {
|
||||
|
||||
public boolean apply(Object source, String name, Object value) {
|
||||
return !propertyFliters.contains(name);
|
||||
}
|
||||
|
||||
});
|
||||
serializer.getPropertyFilters().add((source, name, value) -> !propertyFliters.contains(name));
|
||||
serializer.write(obj);
|
||||
return out.toString();
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,18 +19,14 @@ public class NamedThreadFactory implements ThreadFactory {
|
||||
final private boolean daemon;
|
||||
final private ThreadGroup group;
|
||||
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,
|
||||
Throwable e) {
|
||||
if (e instanceof InterruptedException
|
||||
|| (e.getCause() != null && e.getCause() instanceof InterruptedException)) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.error("from " + t.getName(), e);
|
||||
}
|
||||
};
|
||||
logger.error("from " + t.getName(), e);
|
||||
};
|
||||
|
||||
public NamedThreadFactory(){
|
||||
this(DEFAULT_NAME, true);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public final class UriUtils {
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
String query = uri.getRawQuery();
|
||||
HashMap<String, String> params = new HashMap<String, String>();
|
||||
HashMap<String, String> params = new HashMap<>();
|
||||
@SuppressWarnings("resource")
|
||||
Scanner scan = new Scanner(query);
|
||||
scan.useDelimiter(SPLIT);
|
||||
|
||||
@@ -11,7 +11,6 @@ import org.I0Itec.zkclient.exception.ZkNodeExistsException;
|
||||
import org.I0Itec.zkclient.serialize.ZkSerializer;
|
||||
import org.apache.zookeeper.CreateMode;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MigrateMap;
|
||||
|
||||
/**
|
||||
@@ -23,12 +22,7 @@ import com.google.common.collect.MigrateMap;
|
||||
public class ZkClientx extends ZkClient {
|
||||
|
||||
// 对于zkclient进行一次缓存,避免一个jvm内部使用多个zk connection
|
||||
private static Map<String, ZkClientx> clients = MigrateMap.makeComputingMap(new Function<String, ZkClientx>() {
|
||||
|
||||
public ZkClientx apply(String servers) {
|
||||
return new ZkClientx(servers);
|
||||
}
|
||||
});
|
||||
private static Map<String, ZkClientx> clients = MigrateMap.makeComputingMap(ZkClientx::new);
|
||||
|
||||
public static ZkClientx getZkClient(String servers) {
|
||||
return clients.get(servers);
|
||||
|
||||
@@ -73,12 +73,7 @@ public class ServerRunningMonitor extends AbstractCanalLifeCycle {
|
||||
initRunning();
|
||||
} else {
|
||||
// 否则就是等待delayTime,避免因网络瞬端或者zk异常,导致出现频繁的切换操作
|
||||
delayExector.schedule(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
initRunning();
|
||||
}
|
||||
}, delayTime, TimeUnit.SECONDS);
|
||||
delayExector.schedule(() -> initRunning(), delayTime, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -57,55 +57,43 @@ public class ServerRunningTest extends AbstractZkTest {
|
||||
final ServerRunningMonitor runningMonitor2 = buildServerRunning(countLatch, "127.0.0.1", 2089);
|
||||
final ServerRunningMonitor runningMonitor3 = buildServerRunning(countLatch, "127.0.0.1", 2090);
|
||||
final ExecutorService executor = Executors.newFixedThreadPool(3);
|
||||
executor.submit(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor1.isStart()) {
|
||||
runningMonitor1.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
if (runningMonitor1.check()) {
|
||||
runningMonitor1.stop();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
executor.submit(() -> {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor1.isStart()) {
|
||||
runningMonitor1.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
if (runningMonitor1.check()) {
|
||||
runningMonitor1.stop();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
executor.submit(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor2.isStart()) {
|
||||
runningMonitor2.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
if (runningMonitor2.check()) {
|
||||
runningMonitor2.stop();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
executor.submit(() -> {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor2.isStart()) {
|
||||
runningMonitor2.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
if (runningMonitor2.check()) {
|
||||
runningMonitor2.stop();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
executor.submit(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor3.isStart()) {
|
||||
runningMonitor3.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
if (runningMonitor3.check()) {
|
||||
runningMonitor3.stop();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
executor.submit(() -> {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!runningMonitor3.isStart()) {
|
||||
runningMonitor3.start();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
if (runningMonitor3.check()) {
|
||||
runningMonitor3.stop();
|
||||
}
|
||||
sleep(2000L + RandomUtils.nextInt(500));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
sleep(30000L);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.alibaba.otter.canal.connector.core.filter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -42,7 +41,7 @@ public class AviaterRegexFilter {
|
||||
this.defaultEmptyValue = defaultEmptyValue;
|
||||
List<String> list = null;
|
||||
if (StringUtils.isEmpty(pattern)) {
|
||||
list = new ArrayList<String>();
|
||||
list = new ArrayList<>();
|
||||
} else {
|
||||
String[] ss = StringUtils.split(pattern, SPLIT);
|
||||
list = Arrays.asList(ss);
|
||||
@@ -51,7 +50,7 @@ public class AviaterRegexFilter {
|
||||
// 对pattern按照从长到短的排序
|
||||
// 因为 foo|foot 匹配 foot 会出错,原因是 foot 匹配了 foo 之后,会返回 foo,但是 foo 的长度和 foot
|
||||
// 的长度不一样
|
||||
Collections.sort(list, COMPARATOR);
|
||||
list.sort(COMPARATOR);
|
||||
// 对pattern进行头尾完全匹配
|
||||
list = completionPattern(list);
|
||||
this.pattern = StringUtils.join(list, PATTERN_SPLIT);
|
||||
@@ -66,7 +65,7 @@ public class AviaterRegexFilter {
|
||||
return defaultEmptyValue;
|
||||
}
|
||||
|
||||
Map<String, Object> env = new HashMap<String, Object>();
|
||||
Map<String, Object> env = new HashMap<>();
|
||||
env.put("pattern", pattern);
|
||||
env.put("target", filtered.toLowerCase());
|
||||
return (Boolean) exp.execute(env);
|
||||
@@ -88,13 +87,7 @@ public class AviaterRegexFilter {
|
||||
|
||||
@Override
|
||||
public int compare(String str1, String str2) {
|
||||
if (str1.length() > str2.length()) {
|
||||
return -1;
|
||||
} else if (str1.length() < str2.length()) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return Integer.compare(str2.length(), str1.length());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +105,7 @@ public class AviaterRegexFilter {
|
||||
*/
|
||||
|
||||
private List<String> completionPattern(List<String> patterns) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String pattern : patterns) {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
stringBuffer.append("^");
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
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.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
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 抽象类
|
||||
*
|
||||
@@ -20,7 +20,7 @@ import com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;
|
||||
*/
|
||||
public abstract class AbstractMQProducer implements CanalMQProducer {
|
||||
|
||||
protected MQProperties mqProperties;
|
||||
protected MQProperties mqProperties;
|
||||
|
||||
protected ThreadPoolExecutor sendExecutor;
|
||||
protected ThreadPoolExecutor buildExecutor;
|
||||
@@ -32,21 +32,21 @@ public abstract class AbstractMQProducer implements CanalMQProducer {
|
||||
|
||||
int parallelBuildThreadSize = mqProperties.getParallelBuildThreadSize();
|
||||
buildExecutor = new ThreadPoolExecutor(parallelBuildThreadSize,
|
||||
parallelBuildThreadSize,
|
||||
0,
|
||||
TimeUnit.SECONDS,
|
||||
new ArrayBlockingQueue<Runnable>(parallelBuildThreadSize * 2),
|
||||
new NamedThreadFactory("MQ-Parallel-Builder"),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
parallelBuildThreadSize,
|
||||
0,
|
||||
TimeUnit.SECONDS,
|
||||
new ArrayBlockingQueue<>(parallelBuildThreadSize * 2),
|
||||
new NamedThreadFactory("MQ-Parallel-Builder"),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
|
||||
int parallelSendThreadSize = mqProperties.getParallelSendThreadSize();
|
||||
sendExecutor = new ThreadPoolExecutor(parallelSendThreadSize,
|
||||
parallelSendThreadSize,
|
||||
0,
|
||||
TimeUnit.SECONDS,
|
||||
new ArrayBlockingQueue<Runnable>(parallelSendThreadSize * 2),
|
||||
new NamedThreadFactory("MQ-Parallel-Sender"),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
parallelSendThreadSize,
|
||||
0,
|
||||
TimeUnit.SECONDS,
|
||||
new ArrayBlockingQueue<>(parallelSendThreadSize * 2),
|
||||
new NamedThreadFactory("MQ-Parallel-Sender"),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,52 +77,52 @@ public abstract class AbstractMQProducer implements CanalMQProducer {
|
||||
* canal.mq.timeout = 100 <br/>
|
||||
* canal.mq.access.channel = local <br/>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param 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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
mqProperties.setAliyunUid(Integer.parseInt(aliyunUid));
|
||||
}
|
||||
@@ -132,7 +132,7 @@ public abstract class AbstractMQProducer implements CanalMQProducer {
|
||||
* 兼容下<=1.1.4的mq配置项
|
||||
*/
|
||||
protected void doMoreCompatibleConvert(String oldKey, String newKey, Properties properties) {
|
||||
String value = properties.getProperty(oldKey);
|
||||
String value = PropertiesUtils.getProperty(properties, oldKey);
|
||||
if (StringUtils.isNotEmpty(value)) {
|
||||
properties.setProperty(newKey, value);
|
||||
}
|
||||
|
||||
@@ -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.FlatMessage;
|
||||
import com.alibaba.otter.canal.protocol.Message;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.MigrateMap;
|
||||
@@ -75,64 +74,58 @@ public class MQMessageUtils {
|
||||
|
||||
private static Map<String, List<DynamicTopicData>> dynamicTopicDatas = MigrateMap.makeComputingMap(CacheBuilder.newBuilder()
|
||||
.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) {
|
||||
List<DynamicTopicData> datas = Lists.newArrayList();
|
||||
String[] dynamicTopicArray = StringUtils.split(StringUtils.replace(pkHashConfigs,
|
||||
",",
|
||||
";"),
|
||||
";");
|
||||
// schema.table
|
||||
for (String dynamicTopic : dynamicTopicArray) {
|
||||
DynamicTopicData data = new DynamicTopicData();
|
||||
if (!isWildCard(dynamicTopic)) {
|
||||
data.simpleName = dynamicTopic;
|
||||
} else {
|
||||
if (dynamicTopic.contains("\\.")) {
|
||||
data.tableRegexFilter = new AviaterRegexFilter(dynamicTopic);
|
||||
} else {
|
||||
data.schemaRegexFilter = new AviaterRegexFilter(dynamicTopic);
|
||||
}
|
||||
}
|
||||
datas.add(data);
|
||||
}
|
||||
|
||||
if (!isWildCard(dynamicTopic)) {
|
||||
data.simpleName = dynamicTopic;
|
||||
} else {
|
||||
if (dynamicTopic.contains("\\.")) {
|
||||
data.tableRegexFilter = new AviaterRegexFilter(dynamicTopic);
|
||||
} else {
|
||||
data.schemaRegexFilter = new AviaterRegexFilter(dynamicTopic);
|
||||
}
|
||||
}
|
||||
datas.add(data);
|
||||
}
|
||||
|
||||
return datas;
|
||||
}
|
||||
});
|
||||
return datas;
|
||||
});
|
||||
|
||||
private static Map<String, List<TopicPartitionData>> topicPartitionDatas = MigrateMap.makeComputingMap(CacheBuilder.newBuilder()
|
||||
.softValues(),
|
||||
new Function<String, List<TopicPartitionData>>() {
|
||||
|
||||
public List<TopicPartitionData> apply(String tPConfigs) {
|
||||
List<TopicPartitionData> datas = Lists.newArrayList();
|
||||
String[] tPArray = StringUtils.split(StringUtils.replace(tPConfigs,
|
||||
",",
|
||||
";"),
|
||||
";");
|
||||
for (String tPConfig : tPArray) {
|
||||
TopicPartitionData data = new TopicPartitionData();
|
||||
int i = tPConfig.lastIndexOf(":");
|
||||
if (i > 0) {
|
||||
String tStr = tPConfig.substring(0, i);
|
||||
String pStr = tPConfig.substring(i + 1);
|
||||
if (!isWildCard(tStr)) {
|
||||
data.simpleName = tStr;
|
||||
} else {
|
||||
data.regexFilter = new AviaterRegexFilter(tStr);
|
||||
}
|
||||
if (!StringUtils.isEmpty(pStr) && StringUtils.isNumeric(pStr)) {
|
||||
data.partitionNum = Integer.valueOf(pStr);
|
||||
}
|
||||
datas.add(data);
|
||||
tPConfigs -> {
|
||||
List<TopicPartitionData> datas = Lists.newArrayList();
|
||||
String[] tPArray = StringUtils.split(StringUtils.replace(tPConfigs,
|
||||
",",
|
||||
";"),
|
||||
";");
|
||||
for (String tPConfig : tPArray) {
|
||||
TopicPartitionData data = new TopicPartitionData();
|
||||
int i = tPConfig.lastIndexOf(":");
|
||||
if (i > 0) {
|
||||
String tStr = tPConfig.substring(0, i);
|
||||
String pStr = tPConfig.substring(i + 1);
|
||||
if (!isWildCard(tStr)) {
|
||||
data.simpleName = tStr;
|
||||
} else {
|
||||
data.regexFilter = new AviaterRegexFilter(tStr);
|
||||
}
|
||||
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;
|
||||
for (ByteString byteString : rawEntries) {
|
||||
final int index = i;
|
||||
template.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Entry entry = Entry.parseFrom(byteString);
|
||||
CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue());
|
||||
datas[index] = new EntryRowData();
|
||||
datas[index].entry = entry;
|
||||
datas[index].rowChange = rowChange;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
template.submit(() -> {
|
||||
try {
|
||||
Entry entry = Entry.parseFrom(byteString);
|
||||
RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
|
||||
datas[index] = new EntryRowData();
|
||||
datas[index].entry = entry;
|
||||
datas[index].rowChange = rowChange;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -232,18 +221,14 @@ public class MQMessageUtils {
|
||||
int i = 0;
|
||||
for (Entry entry : message.getEntries()) {
|
||||
final int index = i;
|
||||
template.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue());
|
||||
datas[index] = new EntryRowData();
|
||||
datas[index].entry = entry;
|
||||
datas[index].rowChange = rowChange;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
template.submit(() -> {
|
||||
try {
|
||||
RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
|
||||
datas[index] = new EntryRowData();
|
||||
datas[index].entry = entry;
|
||||
datas[index].rowChange = rowChange;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -679,7 +664,7 @@ public class MQMessageUtils {
|
||||
CanalEntry.Entry entry) {
|
||||
Message message = messageMap.get(topicName);
|
||||
if (message == null) {
|
||||
message = new Message(messageId, new ArrayList<CanalEntry.Entry>());
|
||||
message = new Message(messageId, new ArrayList<>());
|
||||
messageMap.put(topicName, message);
|
||||
}
|
||||
message.getEntries().add(entry);
|
||||
|
||||
@@ -20,6 +20,7 @@ public class URLClassExtensionLoader extends URLClassLoader {
|
||||
}
|
||||
|
||||
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.hadoop."))
|
||||
// {
|
||||
|
||||
@@ -34,8 +34,8 @@ public class CanalMessageSerializerUtil {
|
||||
messageSize += CodedOutputStream.computeInt64Size(1, data.getId());
|
||||
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < rowEntries.size(); i++) {
|
||||
dataSize += CodedOutputStream.computeBytesSizeNoTag(rowEntries.get(i));
|
||||
for (ByteString rowEntry : rowEntries) {
|
||||
dataSize += CodedOutputStream.computeBytesSizeNoTag(rowEntry);
|
||||
}
|
||||
messageSize += dataSize;
|
||||
messageSize += 1 * rowEntries.size();
|
||||
@@ -53,8 +53,8 @@ public class CanalMessageSerializerUtil {
|
||||
output.writeRawVarint32(messageSize);
|
||||
// message
|
||||
output.writeInt64(1, data.getId());
|
||||
for (int i = 0; i < rowEntries.size(); i++) {
|
||||
output.writeBytes(2, rowEntries.get(i));
|
||||
for (ByteString rowEntry : rowEntries) {
|
||||
output.writeBytes(2, rowEntry);
|
||||
}
|
||||
output.checkNoSpaceLeft();
|
||||
return body;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import com.alibaba.otter.canal.common.utils.PropertiesUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.kafka.clients.producer.KafkaProducer;
|
||||
import org.apache.kafka.clients.producer.Producer;
|
||||
@@ -105,15 +106,15 @@ public class CanalKafkaProducer extends AbstractMQProducer implements CanalMQPro
|
||||
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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
kafkaProducerConfig.setJaasFile(jaasFile);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>canal connector module for otter ${project.version}</name>
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.alibaba.otter.canal.common.utils.PropertiesUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -66,13 +67,13 @@ public class CanalRabbitMQConsumer implements CanalMsgConsumer {
|
||||
|
||||
@Override
|
||||
public void init(Properties properties, String topic, String groupId) {
|
||||
this.nameServer = properties.getProperty("rabbitmq.host");
|
||||
this.vhost = properties.getProperty("rabbitmq.virtual.host");
|
||||
this.nameServer = PropertiesUtils.getProperty(properties, "rabbitmq.host");
|
||||
this.vhost = PropertiesUtils.getProperty(properties, "rabbitmq.virtual.host");
|
||||
this.queueName = topic;
|
||||
this.accessKey = properties.getProperty(CanalConstants.CANAL_ALIYUN_ACCESS_KEY);
|
||||
this.secretKey = properties.getProperty(CanalConstants.CANAL_ALIYUN_SECRET_KEY);
|
||||
this.username = properties.getProperty(RabbitMQConstants.RABBITMQ_USERNAME);
|
||||
this.password = properties.getProperty(RabbitMQConstants.RABBITMQ_PASSWORD);
|
||||
this.accessKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_ACCESS_KEY);
|
||||
this.secretKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_SECRET_KEY);
|
||||
this.username = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_USERNAME);
|
||||
this.password = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_PASSWORD);
|
||||
Long resourceOwnerIdPro = (Long) properties.get(RabbitMQConstants.RABBITMQ_RESOURCE_OWNERID);
|
||||
if (resourceOwnerIdPro != null) {
|
||||
this.resourceOwnerId = resourceOwnerIdPro;
|
||||
@@ -90,7 +91,15 @@ public class CanalRabbitMQConsumer implements CanalMsgConsumer {
|
||||
factory.setUsername(username);
|
||||
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.setNetworkRecoveryInterval(5000);
|
||||
factory.setVirtualHost(vhost);
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.otter.canal.common.CanalException;
|
||||
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.MQDestination;
|
||||
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.protocol.FlatMessage;
|
||||
import com.alibaba.otter.canal.protocol.Message;
|
||||
import com.rabbitmq.client.AlreadyClosedException;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
@@ -84,23 +86,23 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
// 兼容下<=1.1.4的mq配置
|
||||
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)) {
|
||||
rabbitMQProperties.setHost(host);
|
||||
}
|
||||
String vhost = properties.getProperty(RabbitMQConstants.RABBITMQ_VIRTUAL_HOST);
|
||||
String vhost = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_VIRTUAL_HOST);
|
||||
if (!StringUtils.isEmpty(vhost)) {
|
||||
rabbitMQProperties.setVirtualHost(vhost);
|
||||
}
|
||||
String exchange = properties.getProperty(RabbitMQConstants.RABBITMQ_EXCHANGE);
|
||||
String exchange = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_EXCHANGE);
|
||||
if (!StringUtils.isEmpty(exchange)) {
|
||||
rabbitMQProperties.setExchange(exchange);
|
||||
}
|
||||
String username = properties.getProperty(RabbitMQConstants.RABBITMQ_USERNAME);
|
||||
String username = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_USERNAME);
|
||||
if (!StringUtils.isEmpty(username)) {
|
||||
rabbitMQProperties.setUsername(username);
|
||||
}
|
||||
String password = properties.getProperty(RabbitMQConstants.RABBITMQ_PASSWORD);
|
||||
String password = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_PASSWORD);
|
||||
if (!StringUtils.isEmpty(password)) {
|
||||
rabbitMQProperties.setPassword(password);
|
||||
}
|
||||
@@ -120,13 +122,7 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
final String topicName = entry.getKey().replace('.', '_');
|
||||
final com.alibaba.otter.canal.protocol.Message messageSub = entry.getValue();
|
||||
|
||||
template.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
send(destination, topicName, messageSub);
|
||||
}
|
||||
});
|
||||
template.submit(() -> send(destination, topicName, messageSub));
|
||||
}
|
||||
|
||||
template.waitForResult();
|
||||
@@ -182,6 +178,8 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
this.connect.close();
|
||||
this.channel.close();
|
||||
super.stop();
|
||||
} catch (AlreadyClosedException ex) {
|
||||
logger.error("Connection is already closed", ex);
|
||||
} catch (IOException | TimeoutException ex) {
|
||||
throw new CanalException("Stop RabbitMQ producer error", ex);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -16,7 +14,7 @@
|
||||
<name>canal connector rocketMQ module for otter ${project.version}</name>
|
||||
|
||||
<properties>
|
||||
<rocketmq_version>4.5.2</rocketmq_version>
|
||||
<rocketmq_version>4.8.0</rocketmq_version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -85,7 +83,7 @@
|
||||
<tasks>
|
||||
<copy todir="${project.basedir}/../../deployer/target/canal/plugin" overwrite="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>
|
||||
</copy>
|
||||
<copy todir="${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin" overwrite="true">
|
||||
|
||||
@@ -17,6 +17,7 @@ public class RocketMQConstants {
|
||||
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_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_BATCH_SIZE = ROOT + "." + "batch.size";
|
||||
|
||||
@@ -17,6 +17,7 @@ public class RocketMQProducerConfig extends MQProperties {
|
||||
private String namesrvAddr;
|
||||
private int retryTimesWhenSendFailed = 0;
|
||||
private boolean vipChannelEnabled = false;
|
||||
private String tag;
|
||||
|
||||
public String getProducerGroup() {
|
||||
return producerGroup;
|
||||
@@ -73,4 +74,12 @@ public class RocketMQProducerConfig extends MQProperties {
|
||||
public void setVipChannelEnabled(boolean vipChannelEnabled) {
|
||||
this.vipChannelEnabled = vipChannelEnabled;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public void setTag(String tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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 org.apache.commons.lang.StringUtils;
|
||||
@@ -25,6 +28,8 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.otter.canal.common.CanalException;
|
||||
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.MQDestination;
|
||||
import com.alibaba.otter.canal.connector.core.producer.MQMessageUtils;
|
||||
@@ -45,10 +50,11 @@ import com.alibaba.otter.canal.protocol.FlatMessage;
|
||||
@SPI("rocketmq")
|
||||
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 static final String CLOUD_ACCESS_CHANNEL = "cloud";
|
||||
private DefaultMQProducer defaultMQProducer;
|
||||
private static final String CLOUD_ACCESS_CHANNEL = "cloud";
|
||||
protected ThreadPoolExecutor sendPartitionExecutor;
|
||||
|
||||
@Override
|
||||
public void init(Properties properties) {
|
||||
@@ -84,6 +90,15 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
} catch (MQClientException 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) {
|
||||
@@ -94,34 +109,41 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
doMoreCompatibleConvert("canal.mq.namespace", "rocketmq.namespace", 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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
rocketMQProperties.setCustomizedTraceTopic(customizedTraceTopic);
|
||||
}
|
||||
String namespace = properties.getProperty(RocketMQConstants.ROCKETMQ_NAMESPACE);
|
||||
String namespace = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_NAMESPACE);
|
||||
if (!StringUtils.isEmpty(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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
rocketMQProperties.setVipChannelEnabled(Boolean.parseBoolean(vipChannelEnabled));
|
||||
}
|
||||
String tag = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_TAG);
|
||||
if (!StringUtils.isEmpty(tag)) {
|
||||
rocketMQProperties.setTag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
// 获取当前topic的分区数
|
||||
Integer partitionNum = MQMessageUtils.parseDynamicTopicPartition(topicName, destination.getDynamicTopicPartitionNum());
|
||||
Integer partitionNum = MQMessageUtils.parseDynamicTopicPartition(topicName,
|
||||
destination.getDynamicTopicPartitionNum());
|
||||
if (partitionNum == null) {
|
||||
partitionNum = destination.getPartitionsNum();
|
||||
}
|
||||
@@ -178,14 +201,16 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
mqProperties.isDatabaseHash());
|
||||
int length = messages.length;
|
||||
|
||||
ExecutorTemplate template = new ExecutorTemplate(sendExecutor);
|
||||
ExecutorTemplate template = new ExecutorTemplate(sendPartitionExecutor);
|
||||
for (int i = 0; i < length; i++) {
|
||||
com.alibaba.otter.canal.protocol.Message dataPartition = messages[i];
|
||||
if (dataPartition != null) {
|
||||
final int index = i;
|
||||
template.submit(() -> {
|
||||
Message data = new Message(topicName, CanalMessageSerializerUtil.serializer(dataPartition,
|
||||
mqProperties.isFilterTransactionEntry()));
|
||||
Message data = new Message(topicName,
|
||||
((RocketMQProducerConfig) this.mqProperties).getTag(),
|
||||
CanalMessageSerializerUtil.serializer(dataPartition,
|
||||
mqProperties.isFilterTransactionEntry()));
|
||||
sendMessage(data, index);
|
||||
});
|
||||
}
|
||||
@@ -194,8 +219,9 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
template.waitForResult();
|
||||
} else {
|
||||
final int partition = destination.getPartition() != null ? destination.getPartition() : 0;
|
||||
Message data = new Message(topicName, CanalMessageSerializerUtil.serializer(message,
|
||||
mqProperties.isFilterTransactionEntry()));
|
||||
Message data = new Message(topicName,
|
||||
((RocketMQProducerConfig) this.mqProperties).getTag(),
|
||||
CanalMessageSerializerUtil.serializer(message, mqProperties.isFilterTransactionEntry()));
|
||||
sendMessage(data, partition);
|
||||
}
|
||||
} else {
|
||||
@@ -217,19 +243,23 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
mqProperties.isDatabaseHash());
|
||||
int length = partitionFlatMessage.length;
|
||||
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++) {
|
||||
final List<FlatMessage> flatMessagePart = partitionFlatMessages.get(i);
|
||||
if (flatMessagePart != null) {
|
||||
if (flatMessagePart != null && flatMessagePart.size() > 0) {
|
||||
final int index = i;
|
||||
template.submit(() -> {
|
||||
List<Message> messages = flatMessagePart.stream()
|
||||
.map(flatMessage -> new Message(topicName, JSON.toJSONBytes(flatMessage,
|
||||
SerializerFeature.WriteMapNullValue)))
|
||||
.map(flatMessage -> new Message(topicName,
|
||||
((RocketMQProducerConfig) this.mqProperties).getTag(),
|
||||
JSON.toJSONBytes(flatMessage, SerializerFeature.WriteMapNullValue)))
|
||||
.collect(Collectors.toList());
|
||||
// 批量发送
|
||||
sendMessage(messages, index);
|
||||
@@ -242,8 +272,9 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
} else {
|
||||
final int partition = destination.getPartition() != null ? destination.getPartition() : 0;
|
||||
List<Message> messages = flatMessages.stream()
|
||||
.map(flatMessage -> new Message(topicName, JSON.toJSONBytes(flatMessage,
|
||||
SerializerFeature.WriteMapNullValue)))
|
||||
.map(flatMessage -> new Message(topicName,
|
||||
((RocketMQProducerConfig) this.mqProperties).getTag(),
|
||||
JSON.toJSONBytes(flatMessage, SerializerFeature.WriteMapNullValue)))
|
||||
.collect(Collectors.toList());
|
||||
// 批量发送
|
||||
sendMessage(messages, partition);
|
||||
@@ -315,6 +346,10 @@ public class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
public void stop() {
|
||||
logger.info("## Stop RocketMQ producer##");
|
||||
this.defaultMQProducer.shutdown();
|
||||
if (sendPartitionExecutor != null) {
|
||||
sendPartitionExecutor.shutdownNow();
|
||||
}
|
||||
|
||||
super.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -107,10 +105,9 @@
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<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">
|
||||
<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>
|
||||
</copy>
|
||||
</tasks>
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
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.impl.ClusterCanalConnector;
|
||||
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.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实例
|
||||
*
|
||||
*
|
||||
* @author rewerma 2020-01-30
|
||||
* @version 1.0.0
|
||||
* @author XuDaojie
|
||||
* @version 1.1.5
|
||||
* @since 1.1.5
|
||||
*/
|
||||
@SPI("tcp")
|
||||
public class CanalTCPConsumer implements CanalMsgConsumer {
|
||||
@@ -42,7 +46,7 @@ public class CanalTCPConsumer implements CanalMsgConsumer {
|
||||
if (batchSizePro != null) {
|
||||
batchSize = Integer.parseInt(batchSizePro);
|
||||
}
|
||||
if (host != null) {
|
||||
if (StringUtils.isNotBlank(host)) {
|
||||
String[] ipPort = host.split(":");
|
||||
SocketAddress sa = new InetSocketAddress(ipPort[0], Integer.parseInt(ipPort[1]));
|
||||
this.canalConnector = new SimpleCanalConnector(sa, username, password, destination);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<version>1.1.5</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
|
||||
@@ -420,11 +420,27 @@ public class JsonConversion {
|
||||
for (int i = 0; i < endIndex; ++i) {
|
||||
char c = data.charAt(i);
|
||||
if (c == '"') {
|
||||
sb.append('\\');
|
||||
sb.append("\\\"");
|
||||
} else if (c == '\n') {
|
||||
sb.append("\\n");
|
||||
} else if (c == '\r') {
|
||||
sb.append("\\r");
|
||||
} 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;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class JsonDiffConversion {
|
||||
public static StringBuilder print_json_diff(LogBuffer buffer, long len, String columnName, int columnIndex,
|
||||
String charsetName) {
|
||||
int position = buffer.position();
|
||||
List<String> operation_names = new ArrayList<String>();
|
||||
List<String> operation_names = new ArrayList<>();
|
||||
while (buffer.hasRemaining()) {
|
||||
int operation_int = buffer.getUint8();
|
||||
if (operation_int >= JSON_DIFF_OPERATION_COUNT) {
|
||||
|
||||
@@ -16,7 +16,7 @@ import com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent;
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -24,7 +24,7 @@ public final class LogContext {
|
||||
|
||||
private GTIDSet gtidSet;
|
||||
|
||||
private GtidLogEvent gtidLogEvent; // save current gtid log event
|
||||
private LogEvent gtidLogEvent; // save current gtid log event
|
||||
|
||||
public LogContext(){
|
||||
this.formatDescription = FormatDescriptionLogEvent.FORMAT_DESCRIPTION_EVENT_5_x;
|
||||
@@ -75,11 +75,11 @@ public final class LogContext {
|
||||
this.gtidSet = gtidSet;
|
||||
}
|
||||
|
||||
public GtidLogEvent getGtidLogEvent() {
|
||||
public LogEvent getGtidLogEvent() {
|
||||
return gtidLogEvent;
|
||||
}
|
||||
|
||||
public void setGtidLogEvent(GtidLogEvent gtidLogEvent) {
|
||||
public void setGtidLogEvent(LogEvent gtidLogEvent) {
|
||||
this.gtidLogEvent = gtidLogEvent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ public final class LogDecoder {
|
||||
buffer.limit(header.getEventLen() - LogEvent.BINLOG_CHECKSUM_LEN);
|
||||
}
|
||||
GTIDSet gtidSet = context.getGtidSet();
|
||||
GtidLogEvent gtidLogEvent = context.getGtidLogEvent();
|
||||
LogEvent gtidLogEvent = context.getGtidLogEvent();
|
||||
switch (header.getType()) {
|
||||
case LogEvent.QUERY_EVENT: {
|
||||
QueryLogEvent event = new QueryLogEvent(header, buffer, descriptionEvent);
|
||||
@@ -185,7 +185,8 @@ public final class LogDecoder {
|
||||
context.putTable(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);
|
||||
/* updating position in context */
|
||||
logPosition.position = header.getLogPos();
|
||||
@@ -193,7 +194,8 @@ public final class LogDecoder {
|
||||
header.putGtid(context.getGtidSet(), gtidLogEvent);
|
||||
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);
|
||||
/* updating position in context */
|
||||
logPosition.position = header.getLogPos();
|
||||
@@ -201,7 +203,8 @@ public final class LogDecoder {
|
||||
header.putGtid(context.getGtidSet(), gtidLogEvent);
|
||||
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);
|
||||
/* updating position in context */
|
||||
logPosition.position = header.getLogPos();
|
||||
@@ -349,30 +352,6 @@ public final class LogDecoder {
|
||||
header.putGtid(context.getGtidSet(), gtidLogEvent);
|
||||
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: {
|
||||
RowsLogEvent event = new UpdateRowsLogEvent(header, buffer, descriptionEvent, true);
|
||||
/* updating position in context */
|
||||
@@ -436,12 +415,26 @@ public final class LogDecoder {
|
||||
MariaGtidLogEvent event = new MariaGtidLogEvent(header, buffer, descriptionEvent);
|
||||
/* updating position in context */
|
||||
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;
|
||||
}
|
||||
case LogEvent.GTID_LIST_EVENT: {
|
||||
MariaGtidListLogEvent event = new MariaGtidListLogEvent(header, buffer, descriptionEvent);
|
||||
/* updating position in context */
|
||||
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;
|
||||
}
|
||||
case LogEvent.START_ENCRYPTION_EVENT: {
|
||||
|
||||
@@ -316,10 +316,11 @@ public final class LogHeader {
|
||||
return gtidMap.get(CURRENT_GTID_LAST_COMMIT);
|
||||
}
|
||||
|
||||
public void putGtid(GTIDSet gtidSet, GtidLogEvent event) {
|
||||
public void putGtid(GTIDSet gtidSet, LogEvent gtidEvent) {
|
||||
if (gtidSet != null) {
|
||||
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_SN, String.valueOf(event.getSequenceNumber()));
|
||||
gtidMap.put(CURRENT_GTID_LAST_COMMIT, String.valueOf(event.getLastCommitted()));
|
||||
|
||||
@@ -601,7 +601,7 @@ public final class TableMapLogEvent extends LogEvent {
|
||||
|
||||
private void parse_signedness(LogBuffer buffer, int length) {
|
||||
// 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++) {
|
||||
int ut = buffer.getUint8();
|
||||
for (int c = 0x80; c != 0; c >>= 1) {
|
||||
@@ -622,7 +622,7 @@ public final class TableMapLogEvent extends LogEvent {
|
||||
// stores collation numbers extracted from field.
|
||||
int limit = buffer.position() + length;
|
||||
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) {
|
||||
int col_index = (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) {
|
||||
// stores collation numbers extracted from field.
|
||||
int limit = buffer.position() + length;
|
||||
List<Integer> datas = new ArrayList<Integer>();
|
||||
List<Integer> datas = new ArrayList<>();
|
||||
while (buffer.hasRemaining() && buffer.position() < limit) {
|
||||
int col_charset = (int) buffer.getPackedLong();
|
||||
datas.add(col_charset);
|
||||
@@ -664,10 +664,10 @@ public final class TableMapLogEvent extends LogEvent {
|
||||
// into a string separate vector. All of them are stored
|
||||
// in 'vec'.
|
||||
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) {
|
||||
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++) {
|
||||
int len1 = (int) buffer.getPackedLong();
|
||||
data.add(buffer.getFixString(len1));
|
||||
@@ -694,7 +694,7 @@ public final class TableMapLogEvent extends LogEvent {
|
||||
// stores geometry column's types extracted from field.
|
||||
int limit = buffer.position() + length;
|
||||
|
||||
List<Integer> datas = new ArrayList<Integer>();
|
||||
List<Integer> datas = new ArrayList<>();
|
||||
while (buffer.hasRemaining() && buffer.position() < limit) {
|
||||
int col_type = (int) buffer.getPackedLong();
|
||||
datas.add(col_type);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
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.LogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent;
|
||||
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
|
||||
* @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){
|
||||
super(header, buffer, descriptionEvent);
|
||||
// do nothing , just ignore log event
|
||||
super(header);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
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.LogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent;
|
||||
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
|
||||
* @since 1.0.17
|
||||
*/
|
||||
public class MariaGtidLogEvent extends IgnorableLogEvent {
|
||||
public class MariaGtidLogEvent extends LogEvent {
|
||||
|
||||
private long gtid;
|
||||
private MariaGtid mariaGtid;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -30,13 +32,14 @@ public class MariaGtidLogEvent extends IgnorableLogEvent {
|
||||
*/
|
||||
|
||||
public MariaGtidLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){
|
||||
super(header, buffer, descriptionEvent);
|
||||
gtid = buffer.getUlong64().longValue();
|
||||
// do nothing , just ignore log event
|
||||
super(header);
|
||||
long sequence = buffer.getUlong64().longValue();
|
||||
long domainId = buffer.getUint32();
|
||||
long serverId = header.getServerId();
|
||||
mariaGtid = new MariaGtid(domainId, serverId, sequence);
|
||||
}
|
||||
|
||||
public long getGtid() {
|
||||
return gtid;
|
||||
public String getGtidStr() {
|
||||
return mariaGtid.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.taobao.tddl.dbsync;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.Statement;
|
||||
@@ -12,8 +11,7 @@ import com.taobao.tddl.dbsync.binlog.LogEvent;
|
||||
public class FetcherPerformanceTest {
|
||||
|
||||
public static void main(String args[]) {
|
||||
DirectLogFetcher fetcher = new DirectLogFetcher();
|
||||
try {
|
||||
try (DirectLogFetcher fetcher = new DirectLogFetcher()) {
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306", "root", "hello");
|
||||
Statement statement = connection.createStatement();
|
||||
@@ -40,11 +38,6 @@ public class FetcherPerformanceTest {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
fetcher.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class LogHeaderTest {
|
||||
final LogHeader objectUnderTest = new LogHeader(type);
|
||||
|
||||
// Assert side effects
|
||||
final HashMap<String, String> hashMap = new HashMap<String, String>();
|
||||
final HashMap<String, String> hashMap = new HashMap<>();
|
||||
Assert.assertEquals(hashMap, objectUnderTest.gtidMap);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user