mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
Compare commits
51 Commits
canal-1.1.
...
canal-1.1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1f5a5a8e4 | ||
|
|
4c906702a6 | ||
|
|
9e715b95bc | ||
|
|
ea8949298f | ||
|
|
ba924b9f1d | ||
|
|
7e0061fe93 | ||
|
|
6440b744f2 | ||
|
|
066b022bb3 | ||
|
|
738f41049f | ||
|
|
0f6b9d156a | ||
|
|
ed754b5203 | ||
|
|
11f89163c1 | ||
|
|
cda330e49e | ||
|
|
f9f810226d | ||
|
|
d4a09704f2 | ||
|
|
34e9440383 | ||
|
|
d623bea71a | ||
|
|
5ea9259f0d | ||
|
|
a216b55010 | ||
|
|
2786e06ccf | ||
|
|
63dfbf65df | ||
|
|
d90066e01b | ||
|
|
69cfbabb10 | ||
|
|
ab30f3bd8d | ||
|
|
681d03fbe7 | ||
|
|
f13cc4ee9f | ||
|
|
252ca0279f | ||
|
|
7241af84f7 | ||
|
|
159457cccd | ||
|
|
d8a70d0c2f | ||
|
|
ec247114fd | ||
|
|
f067f761c7 | ||
|
|
d4c8780f26 | ||
|
|
894ef6e610 | ||
|
|
cc75d3dda4 | ||
|
|
d8169cbf71 | ||
|
|
fccc6bc816 | ||
|
|
97aa441bca | ||
|
|
b8c2a757a0 | ||
|
|
c8de48bbd5 | ||
|
|
08239ef23f | ||
|
|
04a2b6f941 | ||
|
|
5f667c3574 | ||
|
|
bfb8cf4190 | ||
|
|
18c38ee057 | ||
|
|
82b3aed62b | ||
|
|
a04a1912a8 | ||
|
|
5d7d19fdb1 | ||
|
|
9edbe7e827 | ||
|
|
b52c5d149b | ||
|
|
aada80ba38 |
@@ -4,6 +4,8 @@
|
||||

|
||||
[](http://isitmaintained.com/project/alibaba/canal "average time to resolve an issue")
|
||||
[](http://isitmaintained.com/project/alibaba/canal "percentage of issues still open")
|
||||
[](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=canal)
|
||||
|
||||
|
||||
## 简介
|
||||
|
||||
@@ -101,3 +103,5 @@ canal 作为 MySQL binlog 增量获取和解析工具,可将变更记录投递
|
||||
|
||||
## 问题反馈
|
||||
- 报告 issue: [github issues](https://github.com/alibaba/canal/issues)
|
||||
|
||||
本项目的Issues会被同步沉淀至[阿里云开发者社区](https://developer.aliyun.com/ask)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.admin</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ export default {
|
||||
}
|
||||
}
|
||||
const validatePassword = (rule, value, callback) => {
|
||||
if (value.length < 6) {
|
||||
callback(new Error('The password can not be less than 6 digits'))
|
||||
if (value.length < 5) {
|
||||
callback(new Error('The password can not be less than 5 digits'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.admin</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>canal.admin-web</artifactId>
|
||||
@@ -30,6 +30,8 @@
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<!-- 支持arm64需要mysql 8.0,升级为8.0的新版驱动 -->
|
||||
<version>8.0.33</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
|
||||
@@ -59,7 +59,7 @@ esac
|
||||
JavaVersion=`$JAVA -version 2>&1 |awk 'NR==1{ gsub(/"/,""); print $3 }' | awk -F '.' '{print $1}'`
|
||||
str=`file -L $JAVA | grep 64-bit`
|
||||
|
||||
JAVA_OPTS="$JAVA_OPTS -Xss256k -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs"
|
||||
JAVA_OPTS="$JAVA_OPTS -Xss1m -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs"
|
||||
if [ $JavaVersion -ge 11 ] ; then
|
||||
#JAVA_OPTS="$JAVA_OPTS -Xlog:gc*:$base_log/gc.log:time "
|
||||
JAVA_OPTS="$JAVA_OPTS"
|
||||
|
||||
@@ -38,12 +38,12 @@ public class SimpleAdminConnectors {
|
||||
}
|
||||
|
||||
private static String getDesensitizationPassword(String password) {
|
||||
String defaultPassword = "******";
|
||||
String defaultPassword = "*****";
|
||||
|
||||
if (Strings.isNullOrEmpty(password) || password.length() < 6) {
|
||||
if (Strings.isNullOrEmpty(password) || password.length() < 5) {
|
||||
return defaultPassword;
|
||||
} else {
|
||||
return String.format("%s******", password.substring(0, 3));
|
||||
return String.format("%s*****", password.substring(0, 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public class UserServiceImpl implements UserService {
|
||||
|
||||
private static byte[] seeds = "canal is best!".getBytes();
|
||||
|
||||
private static final Integer PASSWORD_LENGTH = 6;
|
||||
private static final Integer PASSWORD_LENGTH = 5;
|
||||
|
||||
public User find4Login(String username, String password) {
|
||||
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
<?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">
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal.admin</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>canal admin module for otter ${project.version}</name>
|
||||
<modules>
|
||||
@@ -18,7 +24,6 @@
|
||||
<java_source_version>1.8</java_source_version>
|
||||
<java_target_version>1.8</java_target_version>
|
||||
<file_encoding>UTF-8</file_encoding>
|
||||
<log4j_version>2.17.0</log4j_version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -26,87 +31,25 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
<version>2.0.0.RELEASE</version>
|
||||
<version>3.0.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>5.0.5.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>5.0.5.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>5.0.5.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>5.0.5.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>5.0.5.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>5.0.5.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>2.0.1.RELEASE</version>
|
||||
<version>2.5.4</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.48</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.6.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>1.8.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.41.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-to-slf4j</artifactId>
|
||||
<version>${log4j_version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -54,11 +54,15 @@
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.diffblue</groupId>
|
||||
<artifactId>deeptestutils</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -73,6 +73,9 @@ public class YamlUtils {
|
||||
PropertySource<?> propertySource = propertySources.get(0);
|
||||
|
||||
Properties properties = new Properties();
|
||||
if (baseProperties != null) {
|
||||
properties.putAll(baseProperties);
|
||||
}
|
||||
|
||||
properties.putAll((Map<?, ?>) propertySource.getSource());
|
||||
|
||||
@@ -82,12 +85,7 @@ public class YamlUtils {
|
||||
entry.setValue(((OriginTrackedValue) value).getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (baseProperties != null) {
|
||||
baseProperties.putAll(properties);
|
||||
properties = baseProperties;
|
||||
}
|
||||
|
||||
|
||||
ConfigurationPropertySource sources = new MapConfigurationPropertySource(properties);
|
||||
Binder binder = new Binder(sources);
|
||||
return binder.bind(prefix, Bindable.of(clazz)).get();
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package com.alibaba.otter.canal.client.adapter.support;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class YamlUtilsTest {
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testLoadConfigToYml() {
|
||||
String configStr="dataSourceKey: defaultDS\n"
|
||||
@@ -17,6 +20,7 @@ public class YamlUtilsTest {
|
||||
+ "outerAdapterKey: mysql1\n"
|
||||
+ "concurrent: true\n"
|
||||
+ "dbMapping:\n"
|
||||
+ " _id: _id\n"
|
||||
+ " database: mytest\n"
|
||||
+ " table: user\n"
|
||||
+ " targetTable: mytest2.user\n"
|
||||
@@ -35,6 +39,7 @@ public class YamlUtilsTest {
|
||||
MappingConfig config = YamlUtils.ymlToObj(null, configStr, MappingConfig.class, null, new Properties());
|
||||
|
||||
Assert.assertNotNull(config);
|
||||
Assert.assertEquals(config.getDbMapping().getId(), "_id");
|
||||
Assert.assertEquals(config.getDestination(), "example");
|
||||
Assert.assertEquals(config.getOuterAdapterKey(), "mysql1");
|
||||
Assert.assertEquals(config.getDbMapping().getDatabase(), "mytest");
|
||||
@@ -104,6 +109,9 @@ public class YamlUtilsTest {
|
||||
}
|
||||
|
||||
private static class DbMapping {
|
||||
|
||||
@Value("${_id}")
|
||||
private String id ;
|
||||
private boolean mirrorDb = false; // 是否镜像库
|
||||
private String database; // 数据库名或schema名
|
||||
private String table; // 表名
|
||||
@@ -225,5 +233,13 @@ public class YamlUtilsTest {
|
||||
public void setAllMapColumns(Map<String, String> allMapColumns) {
|
||||
this.allMapColumns = allMapColumns;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -59,12 +59,12 @@ public class ES6xAdapter extends ESAdapter {
|
||||
public Map<String, Object> count(String task) {
|
||||
ESSyncConfig config = esSyncConfig.get(task);
|
||||
ESSyncConfig.ESMapping mapping = config.getEsMapping();
|
||||
SearchResponse response = this.esConnection.new ESSearchRequest(mapping.get_index(), mapping.get_type()).size(0)
|
||||
SearchResponse response = this.esConnection.new ESSearchRequest(mapping.getIndex(), mapping.getType()).size(0)
|
||||
.getResponse();
|
||||
|
||||
long rowCount = response.getHits().getTotalHits();
|
||||
Map<String, Object> res = new LinkedHashMap<>();
|
||||
res.put("esIndex", mapping.get_index());
|
||||
res.put("esIndex", mapping.getIndex());
|
||||
res.put("count", rowCount);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class ESEtlService extends AbstractEtlService {
|
||||
|
||||
public EtlResult importData(List<String> params) {
|
||||
ESMapping mapping = config.getEsMapping();
|
||||
logger.info("start etl to import data to index: {}", mapping.get_index());
|
||||
logger.info("start etl to import data to index: {}", mapping.getIndex());
|
||||
String sql = mapping.getSql();
|
||||
return importData(sql, params);
|
||||
}
|
||||
@@ -78,7 +78,7 @@ public class ESEtlService extends AbstractEtlService {
|
||||
}
|
||||
|
||||
// 如果是主键字段则不插入
|
||||
if (fieldItem.getFieldName().equals(mapping.get_id())) {
|
||||
if (fieldItem.getFieldName().equals(mapping.getId())) {
|
||||
idVal = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);
|
||||
} else {
|
||||
Object val = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);
|
||||
@@ -117,8 +117,8 @@ public class ESEtlService extends AbstractEtlService {
|
||||
if (idVal != null) {
|
||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||
if (mapping.isUpsert()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
idVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
||||
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
@@ -127,8 +127,8 @@ public class ESEtlService extends AbstractEtlService {
|
||||
|
||||
esBulkRequest.add(esUpdateRequest);
|
||||
} else {
|
||||
ESIndexRequest esIndexRequest = this.esConnection.new ES6xIndexRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESIndexRequest esIndexRequest = this.esConnection.new ES6xIndexRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
idVal.toString()).setSource(esFieldData);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esIndexRequest.setRouting(parentVal);
|
||||
@@ -137,12 +137,12 @@ public class ESEtlService extends AbstractEtlService {
|
||||
}
|
||||
} else {
|
||||
idVal = esFieldData.get(mapping.getPk());
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.get_index(),
|
||||
mapping.get_type()).setQuery(QueryBuilders.termQuery(mapping.getPk(), idVal)).size(10000);
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex(),
|
||||
mapping.getType()).setQuery(QueryBuilders.termQuery(mapping.getPk(), idVal)).size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
esBulkRequest.add(esUpdateRequest);
|
||||
}
|
||||
@@ -160,7 +160,7 @@ public class ESEtlService extends AbstractEtlService {
|
||||
(System.currentTimeMillis() - batchBegin),
|
||||
(System.currentTimeMillis() - esBatchBegin),
|
||||
esBulkRequest.numberOfActions(),
|
||||
mapping.get_index());
|
||||
mapping.getIndex());
|
||||
}
|
||||
batchBegin = System.currentTimeMillis();
|
||||
esBulkRequest.resetBulk();
|
||||
@@ -180,12 +180,12 @@ public class ESEtlService extends AbstractEtlService {
|
||||
(System.currentTimeMillis() - batchBegin),
|
||||
(System.currentTimeMillis() - esBatchBegin),
|
||||
esBulkRequest.numberOfActions(),
|
||||
mapping.get_index());
|
||||
mapping.getIndex());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
errMsg.add(mapping.get_index() + " etl failed! ==>" + e.getMessage());
|
||||
errMsg.add(mapping.getIndex() + " etl failed! ==>" + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return count;
|
||||
|
||||
@@ -66,19 +66,19 @@ public class ES6xTemplate implements ESTemplate {
|
||||
|
||||
@Override
|
||||
public void insert(ESSyncConfig.ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
if (mapping.get_id() != null) {
|
||||
if (mapping.getId() != null) {
|
||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||
if (mapping.isUpsert()) {
|
||||
ESUpdateRequest updateRequest = esConnection.new ES6xUpdateRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESUpdateRequest updateRequest = esConnection.new ES6xUpdateRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
updateRequest.setRouting(parentVal);
|
||||
}
|
||||
getBulk().add(updateRequest);
|
||||
} else {
|
||||
ESIndexRequest indexRequest = esConnection.new ES6xIndexRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESIndexRequest indexRequest = esConnection.new ES6xIndexRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
pkVal.toString()).setSource(esFieldData);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
indexRequest.setRouting(parentVal);
|
||||
@@ -87,13 +87,13 @@ public class ES6xTemplate implements ESTemplate {
|
||||
}
|
||||
commitBulk();
|
||||
} else {
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.get_index(),
|
||||
mapping.get_type()).setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal)).size(10000);
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex(),
|
||||
mapping.getType()).setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal)).size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
getBulk().add(esUpdateRequest);
|
||||
commitBulk();
|
||||
@@ -150,19 +150,19 @@ public class ES6xTemplate implements ESTemplate {
|
||||
|
||||
@Override
|
||||
public void delete(ESSyncConfig.ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
if (mapping.get_id() != null) {
|
||||
ESDeleteRequest esDeleteRequest = this.esConnection.new ES6xDeleteRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
if (mapping.getId() != null) {
|
||||
ESDeleteRequest esDeleteRequest = this.esConnection.new ES6xDeleteRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
pkVal.toString());
|
||||
getBulk().add(esDeleteRequest);
|
||||
commitBulk();
|
||||
} else {
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.get_index(),
|
||||
mapping.get_type()).setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal)).size(10000);
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex(),
|
||||
mapping.getType()).setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal)).size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
getBulk().add(esUpdateRequest);
|
||||
commitBulk();
|
||||
@@ -207,7 +207,7 @@ public class ES6xTemplate implements ESTemplate {
|
||||
public Object getESDataFromRS(ESSyncConfig.ESMapping mapping, ResultSet resultSet,
|
||||
Map<String, Object> esFieldData) throws SQLException {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());
|
||||
@@ -216,7 +216,7 @@ public class ES6xTemplate implements ESTemplate {
|
||||
resultIdVal = value;
|
||||
}
|
||||
|
||||
if (!fieldItem.getFieldName().equals(mapping.get_id())
|
||||
if (!fieldItem.getFieldName().equals(mapping.getId())
|
||||
&& !mapping.getSkips().contains(fieldItem.getFieldName())) {
|
||||
esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);
|
||||
}
|
||||
@@ -231,7 +231,7 @@ public class ES6xTemplate implements ESTemplate {
|
||||
@Override
|
||||
public Object getIdValFromRS(ESSyncConfig.ESMapping mapping, ResultSet resultSet) throws SQLException {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());
|
||||
@@ -248,7 +248,7 @@ public class ES6xTemplate implements ESTemplate {
|
||||
public Object getESDataFromRS(ESSyncConfig.ESMapping mapping, ResultSet resultSet, Map<String, Object> dmlOld,
|
||||
Map<String, Object> esFieldData) throws SQLException {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
if (fieldItem.getFieldName().equals(idFieldName)) {
|
||||
@@ -294,7 +294,7 @@ public class ES6xTemplate implements ESTemplate {
|
||||
public Object getESDataFromDmlData(ESSyncConfig.ESMapping mapping, Map<String, Object> dmlData,
|
||||
Map<String, Object> esFieldData) {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
String columnName = fieldItem.getColumnItems().iterator().next().getColumnName();
|
||||
@@ -304,7 +304,7 @@ public class ES6xTemplate implements ESTemplate {
|
||||
resultIdVal = value;
|
||||
}
|
||||
|
||||
if (!fieldItem.getFieldName().equals(mapping.get_id())
|
||||
if (!fieldItem.getFieldName().equals(mapping.getId())
|
||||
&& !mapping.getSkips().contains(fieldItem.getFieldName())) {
|
||||
esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);
|
||||
}
|
||||
@@ -319,7 +319,7 @@ public class ES6xTemplate implements ESTemplate {
|
||||
public Object getESDataFromDmlData(ESSyncConfig.ESMapping mapping,String owner, Map<String, Object> dmlData,
|
||||
Map<String, Object> dmlOld, Map<String, Object> esFieldData) {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
ColumnItem columnItem = fieldItem.getColumnItems().iterator().next();
|
||||
@@ -353,19 +353,19 @@ public class ES6xTemplate implements ESTemplate {
|
||||
}
|
||||
|
||||
private void append4Update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
if (mapping.get_id() != null) {
|
||||
if (mapping.getId() != null) {
|
||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||
if (mapping.isUpsert()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esUpdateRequest.setRouting(parentVal);
|
||||
}
|
||||
getBulk().add(esUpdateRequest);
|
||||
} else {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
pkVal.toString()).setDoc(esFieldData);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esUpdateRequest.setRouting(parentVal);
|
||||
@@ -373,12 +373,12 @@ public class ES6xTemplate implements ESTemplate {
|
||||
getBulk().add(esUpdateRequest);
|
||||
}
|
||||
} else {
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.get_index(),
|
||||
mapping.get_type()).setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal)).size(10000);
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex(),
|
||||
mapping.getType()).setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal)).size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.get_index(),
|
||||
mapping.get_type(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),
|
||||
mapping.getType(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
getBulk().add(esUpdateRequest);
|
||||
}
|
||||
@@ -394,15 +394,15 @@ public class ES6xTemplate implements ESTemplate {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private String getEsType(ESMapping mapping, String fieldName) {
|
||||
String key = mapping.get_index() + "-" + mapping.get_type();
|
||||
String key = mapping.getIndex() + "-" + mapping.getType();
|
||||
Map<String, String> fieldType = esFieldTypes.get(key);
|
||||
if (fieldType != null) {
|
||||
return fieldType.get(fieldName);
|
||||
} else {
|
||||
MappingMetaData mappingMetaData = esConnection.getMapping(mapping.get_index(), mapping.get_type());
|
||||
MappingMetaData mappingMetaData = esConnection.getMapping(mapping.getIndex(), mapping.getType());
|
||||
|
||||
if (mappingMetaData == null) {
|
||||
throw new IllegalArgumentException("Not found the mapping info of index: " + mapping.get_index());
|
||||
throw new IllegalArgumentException("Not found the mapping info of index: " + mapping.getIndex());
|
||||
}
|
||||
|
||||
fieldType = new LinkedHashMap<>();
|
||||
|
||||
@@ -29,9 +29,9 @@ public class ConfigLoadTest {
|
||||
Assert.assertNotNull(config);
|
||||
Assert.assertEquals("defaultDS", config.getDataSourceKey());
|
||||
ESSyncConfig.ESMapping esMapping = config.getEsMapping();
|
||||
Assert.assertEquals("mytest_user", esMapping.get_index());
|
||||
Assert.assertEquals("_doc", esMapping.get_type());
|
||||
Assert.assertEquals("id", esMapping.get_id());
|
||||
Assert.assertEquals("mytest_user", esMapping.getIndex());
|
||||
Assert.assertEquals("_doc", esMapping.getType());
|
||||
Assert.assertEquals("id", esMapping.getId());
|
||||
Assert.assertNotNull(esMapping.getSql());
|
||||
|
||||
// Map<String, List<ESSyncConfig>> dbTableEsSyncConfig =
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -26,7 +27,7 @@ public class Common {
|
||||
outerAdapterConfig.setProperties(properties);
|
||||
|
||||
ES6xAdapter esAdapter = new ES6xAdapter();
|
||||
esAdapter.init(outerAdapterConfig, null);
|
||||
esAdapter.init(outerAdapterConfig, new Properties());
|
||||
return esAdapter;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -59,11 +59,11 @@ public class ES7xAdapter extends ESAdapter {
|
||||
public Map<String, Object> count(String task) {
|
||||
ESSyncConfig config = esSyncConfig.get(task);
|
||||
ESSyncConfig.ESMapping mapping = config.getEsMapping();
|
||||
SearchResponse response = this.esConnection.new ESSearchRequest(mapping.get_index()).size(0).getResponse();
|
||||
SearchResponse response = this.esConnection.new ESSearchRequest(mapping.getIndex()).size(0).getResponse();
|
||||
|
||||
long rowCount = response.getHits().getTotalHits().value;
|
||||
Map<String, Object> res = new LinkedHashMap<>();
|
||||
res.put("esIndex", mapping.get_index());
|
||||
res.put("esIndex", mapping.getIndex());
|
||||
res.put("count", rowCount);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class ESEtlService extends AbstractEtlService {
|
||||
|
||||
public EtlResult importData(List<String> params) {
|
||||
ESMapping mapping = config.getEsMapping();
|
||||
logger.info("start etl to import data to index: {}", mapping.get_index());
|
||||
logger.info("start etl to import data to index: {}", mapping.getIndex());
|
||||
String sql = mapping.getSql();
|
||||
return importData(sql, params);
|
||||
}
|
||||
@@ -78,7 +78,7 @@ public class ESEtlService extends AbstractEtlService {
|
||||
}
|
||||
|
||||
// 如果是主键字段则不插入
|
||||
if (fieldItem.getFieldName().equals(mapping.get_id())) {
|
||||
if (fieldItem.getFieldName().equals(mapping.getId())) {
|
||||
idVal = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);
|
||||
} else {
|
||||
Object val = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);
|
||||
@@ -118,7 +118,7 @@ public class ESEtlService extends AbstractEtlService {
|
||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||
if (mapping.isUpsert()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
idVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
||||
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
@@ -128,7 +128,7 @@ public class ESEtlService extends AbstractEtlService {
|
||||
esBulkRequest.add(esUpdateRequest);
|
||||
} else {
|
||||
ESIndexRequest esIndexRequest = this.esConnection.new ES7xIndexRequest(
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
idVal.toString()).setSource(esFieldData);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esIndexRequest.setRouting(parentVal);
|
||||
@@ -137,13 +137,13 @@ public class ESEtlService extends AbstractEtlService {
|
||||
}
|
||||
} else {
|
||||
idVal = esFieldData.get(mapping.getPk());
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.get_index())
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())
|
||||
.setQuery(QueryBuilders.termQuery(mapping.getPk(), idVal))
|
||||
.size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
esBulkRequest.add(esUpdateRequest);
|
||||
}
|
||||
@@ -162,7 +162,7 @@ public class ESEtlService extends AbstractEtlService {
|
||||
(System.currentTimeMillis() - batchBegin),
|
||||
(System.currentTimeMillis() - esBatchBegin),
|
||||
esBulkRequest.numberOfActions(),
|
||||
mapping.get_index());
|
||||
mapping.getIndex());
|
||||
}
|
||||
batchBegin = System.currentTimeMillis();
|
||||
esBulkRequest.resetBulk();
|
||||
@@ -182,12 +182,12 @@ public class ESEtlService extends AbstractEtlService {
|
||||
(System.currentTimeMillis() - batchBegin),
|
||||
(System.currentTimeMillis() - esBatchBegin),
|
||||
esBulkRequest.numberOfActions(),
|
||||
mapping.get_index());
|
||||
mapping.getIndex());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
errMsg.add(mapping.get_index() + " etl failed! ==>" + e.getMessage());
|
||||
errMsg.add(mapping.getIndex() + " etl failed! ==>" + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return count;
|
||||
|
||||
@@ -66,17 +66,17 @@ public class ES7xTemplate implements ESTemplate {
|
||||
|
||||
@Override
|
||||
public void insert(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
if (mapping.get_id() != null) {
|
||||
if (mapping.getId() != null) {
|
||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||
if (mapping.isUpsert()) {
|
||||
ESUpdateRequest updateRequest = esConnection.new ES7xUpdateRequest(mapping.get_index(),
|
||||
ESUpdateRequest updateRequest = esConnection.new ES7xUpdateRequest(mapping.getIndex(),
|
||||
pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
updateRequest.setRouting(parentVal);
|
||||
}
|
||||
getBulk().add(updateRequest);
|
||||
} else {
|
||||
ESIndexRequest indexRequest = esConnection.new ES7xIndexRequest(mapping.get_index(), pkVal.toString())
|
||||
ESIndexRequest indexRequest = esConnection.new ES7xIndexRequest(mapping.getIndex(), pkVal.toString())
|
||||
.setSource(esFieldData);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
indexRequest.setRouting(parentVal);
|
||||
@@ -85,13 +85,13 @@ public class ES7xTemplate implements ESTemplate {
|
||||
}
|
||||
commitBulk();
|
||||
} else {
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.get_index())
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())
|
||||
.setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))
|
||||
.size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.get_index(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
getBulk().add(esUpdateRequest);
|
||||
commitBulk();
|
||||
@@ -148,18 +148,18 @@ public class ES7xTemplate implements ESTemplate {
|
||||
|
||||
@Override
|
||||
public void delete(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
if (mapping.get_id() != null) {
|
||||
ESDeleteRequest esDeleteRequest = this.esConnection.new ES7xDeleteRequest(mapping.get_index(),
|
||||
if (mapping.getId() != null) {
|
||||
ESDeleteRequest esDeleteRequest = this.esConnection.new ES7xDeleteRequest(mapping.getIndex(),
|
||||
pkVal.toString());
|
||||
getBulk().add(esDeleteRequest);
|
||||
commitBulk();
|
||||
} else {
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.get_index())
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())
|
||||
.setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))
|
||||
.size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.get_index(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
getBulk().add(esUpdateRequest);
|
||||
commitBulk();
|
||||
@@ -204,7 +204,7 @@ public class ES7xTemplate implements ESTemplate {
|
||||
public Object getESDataFromRS(ESMapping mapping, ResultSet resultSet,
|
||||
Map<String, Object> esFieldData) throws SQLException {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());
|
||||
@@ -213,7 +213,7 @@ public class ES7xTemplate implements ESTemplate {
|
||||
resultIdVal = value;
|
||||
}
|
||||
|
||||
if (!fieldItem.getFieldName().equals(mapping.get_id())
|
||||
if (!fieldItem.getFieldName().equals(mapping.getId())
|
||||
&& !mapping.getSkips().contains(fieldItem.getFieldName())) {
|
||||
esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);
|
||||
}
|
||||
@@ -228,7 +228,7 @@ public class ES7xTemplate implements ESTemplate {
|
||||
@Override
|
||||
public Object getIdValFromRS(ESMapping mapping, ResultSet resultSet) throws SQLException {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());
|
||||
@@ -245,7 +245,7 @@ public class ES7xTemplate implements ESTemplate {
|
||||
public Object getESDataFromRS(ESMapping mapping, ResultSet resultSet, Map<String, Object> dmlOld,
|
||||
Map<String, Object> esFieldData) throws SQLException {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
if (fieldItem.getFieldName().equals(idFieldName)) {
|
||||
@@ -289,7 +289,7 @@ public class ES7xTemplate implements ESTemplate {
|
||||
@Override
|
||||
public Object getESDataFromDmlData(ESMapping mapping, Map<String, Object> dmlData, Map<String, Object> esFieldData) {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
String columnName = fieldItem.getColumnItems().iterator().next().getColumnName();
|
||||
@@ -299,7 +299,7 @@ public class ES7xTemplate implements ESTemplate {
|
||||
resultIdVal = value;
|
||||
}
|
||||
|
||||
if (!fieldItem.getFieldName().equals(mapping.get_id())
|
||||
if (!fieldItem.getFieldName().equals(mapping.getId())
|
||||
&& !mapping.getSkips().contains(fieldItem.getFieldName())) {
|
||||
esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);
|
||||
}
|
||||
@@ -314,7 +314,7 @@ public class ES7xTemplate implements ESTemplate {
|
||||
public Object getESDataFromDmlData(ESMapping mapping,String owner, Map<String, Object> dmlData, Map<String, Object> dmlOld,
|
||||
Map<String, Object> esFieldData) {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
ColumnItem columnItem = fieldItem.getColumnItems().iterator().next();
|
||||
@@ -348,17 +348,17 @@ public class ES7xTemplate implements ESTemplate {
|
||||
}
|
||||
|
||||
private void append4Update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
if (mapping.get_id() != null) {
|
||||
if (mapping.getId() != null) {
|
||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||
if (mapping.isUpsert()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.get_index(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),
|
||||
pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esUpdateRequest.setRouting(parentVal);
|
||||
}
|
||||
getBulk().add(esUpdateRequest);
|
||||
} else {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.get_index(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),
|
||||
pkVal.toString()).setDoc(esFieldData);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esUpdateRequest.setRouting(parentVal);
|
||||
@@ -366,12 +366,12 @@ public class ES7xTemplate implements ESTemplate {
|
||||
getBulk().add(esUpdateRequest);
|
||||
}
|
||||
} else {
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.get_index())
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())
|
||||
.setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))
|
||||
.size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.get_index(),
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
getBulk().add(esUpdateRequest);
|
||||
}
|
||||
@@ -387,15 +387,15 @@ public class ES7xTemplate implements ESTemplate {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private String getEsType(ESMapping mapping, String fieldName) {
|
||||
String key = mapping.get_index() + "-" + mapping.get_type();
|
||||
String key = mapping.getIndex() + "-" + mapping.getType();
|
||||
Map<String, String> fieldType = esFieldTypes.get(key);
|
||||
if (fieldType != null) {
|
||||
return fieldType.get(fieldName);
|
||||
} else {
|
||||
MappingMetaData mappingMetaData = esConnection.getMapping(mapping.get_index());
|
||||
MappingMetaData mappingMetaData = esConnection.getMapping(mapping.getIndex());
|
||||
|
||||
if (mappingMetaData == null) {
|
||||
throw new IllegalArgumentException("Not found the mapping info of index: " + mapping.get_index());
|
||||
throw new IllegalArgumentException("Not found the mapping info of index: " + mapping.getIndex());
|
||||
}
|
||||
|
||||
fieldType = new LinkedHashMap<>();
|
||||
|
||||
93
client-adapter/es8x/pom.xml
Normal file
93
client-adapter/es8x/pom.xml
Normal file
@@ -0,0 +1,93 @@
|
||||
<?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">
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>client-adapter.es8x</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>canal client adapter es v8x module for otter ${project.version}</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>client-adapter.common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>client-adapter.escore</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>co.elastic.clients</groupId>
|
||||
<artifactId>elasticsearch-java</artifactId>
|
||||
<version>8.6.2</version>
|
||||
</dependency>
|
||||
<!--<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-client</artifactId>
|
||||
<version>8.6.2</version>
|
||||
</dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
<version>7.17.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<copy todir="${project.basedir}/../launcher/target/classes/es8" overwrite="true">
|
||||
<fileset dir="${project.basedir}/target/classes/es8" erroronmissingdir="true">
|
||||
<include name="*.yml" />
|
||||
</fileset>
|
||||
</copy>
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.alibaba.otter.canal.client.adapter.es8x;
|
||||
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.ESAdapter;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.es8x.etl.ESEtlService;
|
||||
import com.alibaba.otter.canal.client.adapter.es8x.support.ES8xTemplate;
|
||||
import com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection;
|
||||
import com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.support.EtlResult;
|
||||
import com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.support.SPI;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* ES 8.x 外部适配器
|
||||
*
|
||||
* @author ymz 2013-02-23
|
||||
* @version 1.0.0
|
||||
*/
|
||||
@SPI("es8")
|
||||
public class ES8xAdapter extends ESAdapter {
|
||||
|
||||
private ESConnection esConnection;
|
||||
|
||||
public ESConnection getEsConnection() {
|
||||
return esConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(OuterAdapterConfig configuration, Properties envProperties) {
|
||||
try {
|
||||
Map<String, String> properties = configuration.getProperties();
|
||||
|
||||
String[] hostArray = configuration.getHosts().split(",");
|
||||
esConnection = new ESConnection(hostArray, properties);
|
||||
|
||||
this.esTemplate = new ES8xTemplate(esConnection);
|
||||
|
||||
envProperties.put("es.version", "es8");
|
||||
super.init(configuration, envProperties);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> count(String task) {
|
||||
ESSyncConfig config = esSyncConfig.get(task);
|
||||
ESSyncConfig.ESMapping mapping = config.getEsMapping();
|
||||
SearchResponse response = this.esConnection.new ESSearchRequest(mapping.getIndex()).size(0).getResponse();
|
||||
|
||||
long rowCount = response.getHits().getTotalHits().value;
|
||||
Map<String, Object> res = new LinkedHashMap<>();
|
||||
res.put("esIndex", mapping.getIndex());
|
||||
res.put("count", rowCount);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EtlResult etl(String task, List<String> params) {
|
||||
EtlResult etlResult = new EtlResult();
|
||||
ESSyncConfig config = esSyncConfig.get(task);
|
||||
if (config != null) {
|
||||
DataSource dataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());
|
||||
ESEtlService esEtlService = new ESEtlService(esConnection, config);
|
||||
if (dataSource != null) {
|
||||
return esEtlService.importData(params);
|
||||
} else {
|
||||
etlResult.setSucceeded(false);
|
||||
etlResult.setErrorMessage("DataSource not found");
|
||||
return etlResult;
|
||||
}
|
||||
} else {
|
||||
StringBuilder resultMsg = new StringBuilder();
|
||||
boolean resSuccess = true;
|
||||
for (ESSyncConfig configTmp : esSyncConfig.values()) {
|
||||
// 取所有的destination为task的配置
|
||||
if (configTmp.getDestination().equals(task)) {
|
||||
ESEtlService esEtlService = new ESEtlService(esConnection, configTmp);
|
||||
EtlResult etlRes = esEtlService.importData(params);
|
||||
if (!etlRes.getSucceeded()) {
|
||||
resSuccess = false;
|
||||
resultMsg.append(etlRes.getErrorMessage()).append("\n");
|
||||
} else {
|
||||
resultMsg.append(etlRes.getResultMessage()).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resultMsg.length() > 0) {
|
||||
etlResult.setSucceeded(resSuccess);
|
||||
if (resSuccess) {
|
||||
etlResult.setResultMessage(resultMsg.toString());
|
||||
} else {
|
||||
etlResult.setErrorMessage(resultMsg.toString());
|
||||
}
|
||||
return etlResult;
|
||||
}
|
||||
}
|
||||
etlResult.setSucceeded(false);
|
||||
etlResult.setErrorMessage("Task not found");
|
||||
return etlResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
if (esConnection != null) {
|
||||
esConnection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package com.alibaba.otter.canal.client.adapter.es8x.etl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
|
||||
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.FieldItem;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESBulkResponse;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESIndexRequest;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESUpdateRequest;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;
|
||||
import com.alibaba.otter.canal.client.adapter.es8x.support.ES8xTemplate;
|
||||
import com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection;
|
||||
import com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection.ESSearchRequest;
|
||||
import com.alibaba.otter.canal.client.adapter.support.AbstractEtlService;
|
||||
import com.alibaba.otter.canal.client.adapter.support.AdapterConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.support.EtlResult;
|
||||
import com.alibaba.otter.canal.client.adapter.support.Util;
|
||||
|
||||
/**
|
||||
* ES ETL Service
|
||||
*
|
||||
* @author rewerma 2018-11-01
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class ESEtlService extends AbstractEtlService {
|
||||
|
||||
private ESConnection esConnection;
|
||||
private ESTemplate esTemplate;
|
||||
private ESSyncConfig config;
|
||||
|
||||
public ESEtlService(ESConnection esConnection, ESSyncConfig config){
|
||||
super("ES", config);
|
||||
this.esConnection = esConnection;
|
||||
this.esTemplate = new ES8xTemplate(esConnection);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public EtlResult importData(List<String> params) {
|
||||
ESMapping mapping = config.getEsMapping();
|
||||
logger.info("start etl to import data to index: {}", mapping.getIndex());
|
||||
String sql = mapping.getSql();
|
||||
return importData(sql, params);
|
||||
}
|
||||
|
||||
protected boolean executeSqlImport(DataSource ds, String sql, List<Object> values,
|
||||
AdapterConfig.AdapterMapping adapterMapping, AtomicLong impCount,
|
||||
List<String> errMsg) {
|
||||
try {
|
||||
ESMapping mapping = (ESMapping) adapterMapping;
|
||||
Util.sqlRS(ds, sql, values, rs -> {
|
||||
int count = 0;
|
||||
try {
|
||||
ESBulkRequest esBulkRequest = this.esConnection.new ES8xBulkRequest();
|
||||
|
||||
long batchBegin = System.currentTimeMillis();
|
||||
while (rs.next()) {
|
||||
Map<String, Object> esFieldData = new LinkedHashMap<>();
|
||||
Object idVal = null;
|
||||
for (FieldItem fieldItem : mapping.getSchemaItem().getSelectFields().values()) {
|
||||
|
||||
String fieldName = fieldItem.getFieldName();
|
||||
if (mapping.getSkips().contains(fieldName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果是主键字段则不插入
|
||||
if (fieldItem.getFieldName().equals(mapping.getId())) {
|
||||
idVal = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);
|
||||
} else {
|
||||
Object val = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);
|
||||
esFieldData.put(Util.cleanColumn(fieldName), val);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!mapping.getRelations().isEmpty()) {
|
||||
mapping.getRelations().forEach((relationField, relationMapping) -> {
|
||||
Map<String, Object> relations = new HashMap<>();
|
||||
relations.put("name", relationMapping.getName());
|
||||
if (StringUtils.isNotEmpty(relationMapping.getParent())) {
|
||||
FieldItem parentFieldItem = mapping.getSchemaItem()
|
||||
.getSelectFields()
|
||||
.get(relationMapping.getParent());
|
||||
Object parentVal;
|
||||
try {
|
||||
parentVal = esTemplate.getValFromRS(mapping,
|
||||
rs,
|
||||
parentFieldItem.getFieldName(),
|
||||
parentFieldItem.getFieldName());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (parentVal != null) {
|
||||
relations.put("parent", parentVal.toString());
|
||||
esFieldData.put("$parent_routing", parentVal.toString());
|
||||
|
||||
}
|
||||
}
|
||||
esFieldData.put(Util.cleanColumn(relationField), relations);
|
||||
});
|
||||
}
|
||||
|
||||
if (idVal != null) {
|
||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||
if (mapping.isUpsert()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(
|
||||
mapping.getIndex(),
|
||||
idVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
||||
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esUpdateRequest.setRouting(parentVal);
|
||||
}
|
||||
|
||||
esBulkRequest.add(esUpdateRequest);
|
||||
} else {
|
||||
ESIndexRequest esIndexRequest = this.esConnection.new ES8xIndexRequest(
|
||||
mapping.getIndex(),
|
||||
idVal.toString()).setSource(esFieldData);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esIndexRequest.setRouting(parentVal);
|
||||
}
|
||||
esBulkRequest.add(esIndexRequest);
|
||||
}
|
||||
} else {
|
||||
idVal = esFieldData.get(mapping.getPk());
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())
|
||||
.setQuery(QueryBuilders.termQuery(mapping.getPk(), idVal))
|
||||
.size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(
|
||||
mapping.getIndex(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
esBulkRequest.add(esUpdateRequest);
|
||||
}
|
||||
}
|
||||
|
||||
if (esBulkRequest.numberOfActions() % mapping.getCommitBatch() == 0
|
||||
&& esBulkRequest.numberOfActions() > 0) {
|
||||
long esBatchBegin = System.currentTimeMillis();
|
||||
ESBulkResponse rp = esBulkRequest.bulk();
|
||||
if (rp.hasFailures()) {
|
||||
rp.processFailBulkResponse("全量数据 etl 异常 ");
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("全量数据批量导入批次耗时: {}, es执行时间: {}, 批次大小: {}, index; {}",
|
||||
(System.currentTimeMillis() - batchBegin),
|
||||
(System.currentTimeMillis() - esBatchBegin),
|
||||
esBulkRequest.numberOfActions(),
|
||||
mapping.getIndex());
|
||||
}
|
||||
batchBegin = System.currentTimeMillis();
|
||||
esBulkRequest.resetBulk();
|
||||
}
|
||||
count++;
|
||||
impCount.incrementAndGet();
|
||||
}
|
||||
|
||||
if (esBulkRequest.numberOfActions() > 0) {
|
||||
long esBatchBegin = System.currentTimeMillis();
|
||||
ESBulkResponse rp = esBulkRequest.bulk();
|
||||
if (rp.hasFailures()) {
|
||||
rp.processFailBulkResponse("全量数据 etl 异常 ");
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("全量数据批量导入最后批次耗时: {}, es执行时间: {}, 批次大小: {}, index; {}",
|
||||
(System.currentTimeMillis() - batchBegin),
|
||||
(System.currentTimeMillis() - esBatchBegin),
|
||||
esBulkRequest.numberOfActions(),
|
||||
mapping.getIndex());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
errMsg.add(mapping.getIndex() + " etl failed! ==>" + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return count;
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
package com.alibaba.otter.canal.client.adapter.es8x.support;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.cluster.metadata.MappingMetadata;
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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;
|
||||
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.support.ESBulkRequest;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESBulkResponse;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESDeleteRequest;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESIndexRequest;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESUpdateRequest;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESSyncUtil;
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;
|
||||
import com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection.ESSearchRequest;
|
||||
import com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.support.Util;
|
||||
|
||||
public class ES8xTemplate implements ESTemplate {
|
||||
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(ESTemplate.class);
|
||||
|
||||
private static final int MAX_BATCH_SIZE = 1000;
|
||||
|
||||
private ESConnection esConnection;
|
||||
|
||||
private ESBulkRequest esBulkRequest;
|
||||
|
||||
// es 字段类型本地缓存
|
||||
private static ConcurrentMap<String, Map<String, String>> esFieldTypes = new ConcurrentHashMap<>();
|
||||
|
||||
public ES8xTemplate(ESConnection esConnection){
|
||||
this.esConnection = esConnection;
|
||||
this.esBulkRequest = this.esConnection.new ES8xBulkRequest();
|
||||
}
|
||||
|
||||
public ESBulkRequest getBulk() {
|
||||
return esBulkRequest;
|
||||
}
|
||||
|
||||
public void resetBulkRequestBuilder() {
|
||||
this.esBulkRequest.resetBulk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
if (mapping.getId() != null) {
|
||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||
if (mapping.isUpsert()) {
|
||||
ESUpdateRequest updateRequest = esConnection.new ES8xUpdateRequest(mapping.getIndex(),
|
||||
pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
updateRequest.setRouting(parentVal);
|
||||
}
|
||||
getBulk().add(updateRequest);
|
||||
} else {
|
||||
ESIndexRequest indexRequest = esConnection.new ES8xIndexRequest(mapping.getIndex(), pkVal.toString())
|
||||
.setSource(esFieldData);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
indexRequest.setRouting(parentVal);
|
||||
}
|
||||
getBulk().add(indexRequest);
|
||||
}
|
||||
commitBulk();
|
||||
} else {
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())
|
||||
.setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))
|
||||
.size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
getBulk().add(esUpdateRequest);
|
||||
commitBulk();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
Map<String, Object> esFieldDataTmp = new LinkedHashMap<>(esFieldData.size());
|
||||
esFieldData.forEach((k, v) -> esFieldDataTmp.put(Util.cleanColumn(k), v));
|
||||
append4Update(mapping, pkVal, esFieldDataTmp);
|
||||
commitBulk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateByQuery(ESSyncConfig config, Map<String, Object> paramsTmp, Map<String, Object> esFieldData) {
|
||||
if (paramsTmp.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ESMapping mapping = config.getEsMapping();
|
||||
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
|
||||
paramsTmp.forEach((fieldName, value) -> queryBuilder.must(QueryBuilders.termsQuery(fieldName, value)));
|
||||
|
||||
// 查询sql批量更新
|
||||
DataSource ds = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());
|
||||
StringBuilder sql = new StringBuilder("SELECT * FROM (" + mapping.getSql() + ") _v WHERE ");
|
||||
List<Object> values = new ArrayList<>();
|
||||
paramsTmp.forEach((fieldName, value) -> {
|
||||
sql.append("_v.").append(fieldName).append("=? AND ");
|
||||
values.add(value);
|
||||
});
|
||||
// TODO 直接外部包裹sql会导致全表扫描性能低, 待优化拼接内部where条件
|
||||
int len = sql.length();
|
||||
sql.delete(len - 4, len);
|
||||
Integer syncCount = (Integer) Util.sqlRS(ds, sql.toString(), values, rs -> {
|
||||
int count = 0;
|
||||
try {
|
||||
while (rs.next()) {
|
||||
Object idVal = getIdValFromRS(mapping, rs);
|
||||
append4Update(mapping, idVal, esFieldData);
|
||||
commitBulk();
|
||||
count++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return count;
|
||||
});
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Update ES by query affected {} records", syncCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
if (mapping.getId() != null) {
|
||||
ESDeleteRequest esDeleteRequest = this.esConnection.new ES8xDeleteRequest(mapping.getIndex(),
|
||||
pkVal.toString());
|
||||
getBulk().add(esDeleteRequest);
|
||||
commitBulk();
|
||||
} else {
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())
|
||||
.setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))
|
||||
.size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
getBulk().add(esUpdateRequest);
|
||||
commitBulk();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() {
|
||||
if (getBulk().numberOfActions() > 0) {
|
||||
ESBulkResponse response = getBulk().bulk();
|
||||
if (response.hasFailures()) {
|
||||
response.processFailBulkResponse("ES sync commit error ");
|
||||
}
|
||||
resetBulkRequestBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValFromRS(ESMapping mapping, ResultSet resultSet, String fieldName,
|
||||
String columnName) throws SQLException {
|
||||
fieldName = Util.cleanColumn(fieldName);
|
||||
columnName = Util.cleanColumn(columnName);
|
||||
String esType = getEsType(mapping, fieldName);
|
||||
|
||||
Object value = resultSet.getObject(columnName);
|
||||
if (value instanceof Boolean) {
|
||||
if (!"boolean".equals(esType)) {
|
||||
value = resultSet.getByte(columnName);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是对象类型
|
||||
if (mapping.getObjFields().containsKey(fieldName)) {
|
||||
return ESSyncUtil.convertToEsObj(value, mapping.getObjFields().get(fieldName));
|
||||
} else {
|
||||
return ESSyncUtil.typeConvert(value, esType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getESDataFromRS(ESMapping mapping, ResultSet resultSet,
|
||||
Map<String, Object> esFieldData) throws SQLException {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());
|
||||
|
||||
if (fieldItem.getFieldName().equals(idFieldName)) {
|
||||
resultIdVal = value;
|
||||
}
|
||||
|
||||
if (!fieldItem.getFieldName().equals(mapping.getId())
|
||||
&& !mapping.getSkips().contains(fieldItem.getFieldName())) {
|
||||
esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加父子文档关联信息
|
||||
putRelationDataFromRS(mapping, schemaItem, resultSet, esFieldData);
|
||||
|
||||
return resultIdVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getIdValFromRS(ESMapping mapping, ResultSet resultSet) throws SQLException {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());
|
||||
|
||||
if (fieldItem.getFieldName().equals(idFieldName)) {
|
||||
resultIdVal = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return resultIdVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getESDataFromRS(ESMapping mapping, ResultSet resultSet, Map<String, Object> dmlOld,
|
||||
Map<String, Object> esFieldData) throws SQLException {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
if (fieldItem.getFieldName().equals(idFieldName)) {
|
||||
resultIdVal = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());
|
||||
}
|
||||
|
||||
for (ColumnItem columnItem : fieldItem.getColumnItems()) {
|
||||
if (dmlOld.containsKey(columnItem.getColumnName())
|
||||
&& !mapping.getSkips().contains(fieldItem.getFieldName())) {
|
||||
esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()),
|
||||
getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加父子文档关联信息
|
||||
putRelationDataFromRS(mapping, schemaItem, resultSet, esFieldData);
|
||||
|
||||
return resultIdVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValFromData(ESMapping mapping, Map<String, Object> dmlData, String fieldName, String columnName) {
|
||||
String esType = getEsType(mapping, fieldName);
|
||||
Object value = dmlData.get(columnName);
|
||||
if (value instanceof Byte) {
|
||||
if ("boolean".equals(esType)) {
|
||||
value = ((Byte) value).intValue() != 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是对象类型
|
||||
if (mapping.getObjFields().containsKey(fieldName)) {
|
||||
return ESSyncUtil.convertToEsObj(value, mapping.getObjFields().get(fieldName));
|
||||
} else {
|
||||
return ESSyncUtil.typeConvert(value, esType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getESDataFromDmlData(ESMapping mapping, Map<String, Object> dmlData,
|
||||
Map<String, Object> esFieldData) {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
String columnName = fieldItem.getColumnItems().iterator().next().getColumnName();
|
||||
Object value = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);
|
||||
|
||||
if (fieldItem.getFieldName().equals(idFieldName)) {
|
||||
resultIdVal = value;
|
||||
}
|
||||
|
||||
if (!fieldItem.getFieldName().equals(mapping.getId())
|
||||
&& !mapping.getSkips().contains(fieldItem.getFieldName())) {
|
||||
esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加父子文档关联信息
|
||||
putRelationData(mapping, schemaItem, dmlData, esFieldData);
|
||||
return resultIdVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getESDataFromDmlData(ESMapping mapping, String owner, Map<String, Object> dmlData,
|
||||
Map<String, Object> dmlOld, Map<String, Object> esFieldData) {
|
||||
SchemaItem schemaItem = mapping.getSchemaItem();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
Object resultIdVal = null;
|
||||
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
|
||||
ColumnItem columnItem = fieldItem.getColumnItems().iterator().next();
|
||||
if (!columnItem.getOwner().equals(owner)) {
|
||||
continue;
|
||||
}
|
||||
String columnName = columnItem.getColumnName();
|
||||
|
||||
if (fieldItem.getFieldName().equals(idFieldName)) {
|
||||
resultIdVal = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);
|
||||
}
|
||||
|
||||
if (dmlOld.containsKey(columnName) && !mapping.getSkips().contains(fieldItem.getFieldName())) {
|
||||
esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()),
|
||||
getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName));
|
||||
}
|
||||
}
|
||||
|
||||
// 添加父子文档关联信息
|
||||
putRelationData(mapping, schemaItem, dmlOld, esFieldData);
|
||||
return resultIdVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果大于批量数则提交批次
|
||||
*/
|
||||
private void commitBulk() {
|
||||
if (getBulk().numberOfActions() >= MAX_BATCH_SIZE) {
|
||||
commit();
|
||||
}
|
||||
}
|
||||
|
||||
private void append4Update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {
|
||||
if (mapping.getId() != null) {
|
||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||
if (mapping.isUpsert()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),
|
||||
pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esUpdateRequest.setRouting(parentVal);
|
||||
}
|
||||
getBulk().add(esUpdateRequest);
|
||||
} else {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),
|
||||
pkVal.toString()).setDoc(esFieldData);
|
||||
if (StringUtils.isNotEmpty(parentVal)) {
|
||||
esUpdateRequest.setRouting(parentVal);
|
||||
}
|
||||
getBulk().add(esUpdateRequest);
|
||||
}
|
||||
} else {
|
||||
ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())
|
||||
.setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))
|
||||
.size(10000);
|
||||
SearchResponse response = esSearchRequest.getResponse();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),
|
||||
hit.getId()).setDoc(esFieldData);
|
||||
getBulk().add(esUpdateRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取es mapping中的属性类型
|
||||
*
|
||||
* @param mapping mapping配置
|
||||
* @param fieldName 属性名
|
||||
* @return 类型
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private String getEsType(ESMapping mapping, String fieldName) {
|
||||
String key = mapping.getIndex() + "-" + mapping.getType();
|
||||
Map<String, String> fieldType = esFieldTypes.get(key);
|
||||
if (fieldType != null) {
|
||||
return fieldType.get(fieldName);
|
||||
} else {
|
||||
MappingMetadata mappingMetaData = esConnection.getMapping(mapping.getIndex());
|
||||
|
||||
if (mappingMetaData == null) {
|
||||
throw new IllegalArgumentException("Not found the mapping info of index: " + mapping.getIndex());
|
||||
}
|
||||
|
||||
fieldType = new LinkedHashMap<>();
|
||||
|
||||
Map<String, Object> sourceMap = mappingMetaData.getSourceAsMap();
|
||||
Map<String, Object> esMapping = (Map<String, Object>) sourceMap.get("properties");
|
||||
for (Map.Entry<String, Object> entry : esMapping.entrySet()) {
|
||||
Map<String, Object> value = (Map<String, Object>) entry.getValue();
|
||||
if (value.containsKey("properties")) {
|
||||
fieldType.put(entry.getKey(), "object");
|
||||
} else {
|
||||
fieldType.put(entry.getKey(), (String) value.get("type"));
|
||||
}
|
||||
}
|
||||
esFieldTypes.put(key, fieldType);
|
||||
|
||||
return fieldType.get(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
private void putRelationDataFromRS(ESMapping mapping, SchemaItem schemaItem, ResultSet resultSet,
|
||||
Map<String, Object> esFieldData) {
|
||||
// 添加父子文档关联信息
|
||||
if (!mapping.getRelations().isEmpty()) {
|
||||
mapping.getRelations().forEach((relationField, relationMapping) -> {
|
||||
Map<String, Object> relations = new HashMap<>();
|
||||
relations.put("name", relationMapping.getName());
|
||||
if (StringUtils.isNotEmpty(relationMapping.getParent())) {
|
||||
FieldItem parentFieldItem = schemaItem.getSelectFields().get(relationMapping.getParent());
|
||||
Object parentVal;
|
||||
try {
|
||||
parentVal = getValFromRS(mapping,
|
||||
resultSet,
|
||||
parentFieldItem.getFieldName(),
|
||||
parentFieldItem.getFieldName());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (parentVal != null) {
|
||||
relations.put("parent", parentVal.toString());
|
||||
esFieldData.put("$parent_routing", parentVal.toString());
|
||||
|
||||
}
|
||||
}
|
||||
esFieldData.put(relationField, relations);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void putRelationData(ESMapping mapping, SchemaItem schemaItem, Map<String, Object> dmlData,
|
||||
Map<String, Object> esFieldData) {
|
||||
// 添加父子文档关联信息
|
||||
if (!mapping.getRelations().isEmpty()) {
|
||||
mapping.getRelations().forEach((relationField, relationMapping) -> {
|
||||
Map<String, Object> relations = new HashMap<>();
|
||||
relations.put("name", relationMapping.getName());
|
||||
if (StringUtils.isNotEmpty(relationMapping.getParent())) {
|
||||
FieldItem parentFieldItem = schemaItem.getSelectFields().get(relationMapping.getParent());
|
||||
String columnName = parentFieldItem.getColumnItems().iterator().next().getColumnName();
|
||||
Object parentVal = getValFromData(mapping, dmlData, parentFieldItem.getFieldName(), columnName);
|
||||
if (parentVal != null) {
|
||||
relations.put("parent", parentVal.toString());
|
||||
esFieldData.put("$parent_routing", parentVal.toString());
|
||||
|
||||
}
|
||||
}
|
||||
esFieldData.put(relationField, relations);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
package com.alibaba.otter.canal.client.adapter.es8x.support;
|
||||
|
||||
import java.io.IOException;
|
||||
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;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.elasticsearch.action.bulk.BulkItemResponse;
|
||||
import org.elasticsearch.action.bulk.BulkRequest;
|
||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
||||
import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.elasticsearch.action.delete.DeleteRequest;
|
||||
import org.elasticsearch.action.delete.DeleteRequestBuilder;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.update.UpdateRequest;
|
||||
import org.elasticsearch.action.update.UpdateRequestBuilder;
|
||||
import org.elasticsearch.client.*;
|
||||
import org.elasticsearch.client.indices.GetMappingsRequest;
|
||||
import org.elasticsearch.client.indices.GetMappingsResponse;
|
||||
import org.elasticsearch.cluster.metadata.MappingMetadata;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;
|
||||
|
||||
/**
|
||||
* ES 连接器, 只支持 Rest 方式
|
||||
*
|
||||
* @author ymz 2023-03-02
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class ESConnection {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ESConnection.class);
|
||||
|
||||
private RestHighLevelClient restHighLevelClient;
|
||||
|
||||
public ESConnection(String[] hosts, Map<String, String> properties) throws UnknownHostException{
|
||||
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(":")) {
|
||||
String[] nameAndPwdArr = nameAndPwd.split(":");
|
||||
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
|
||||
credentialsProvider.setCredentials(AuthScope.ANY,
|
||||
new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1]));
|
||||
restClientBuilder.setHttpClientConfigCallback(
|
||||
httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
|
||||
}
|
||||
restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build()).setApiCompatibilityMode(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
restHighLevelClient.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public MappingMetadata getMapping(String index) {
|
||||
MappingMetadata mappingMetaData = null;
|
||||
|
||||
Map<String, MappingMetadata> mappings;
|
||||
try {
|
||||
GetMappingsRequest request = new GetMappingsRequest();
|
||||
request.indices(index);
|
||||
GetMappingsResponse response = restHighLevelClient.indices().getMapping(request, RequestOptions.DEFAULT);
|
||||
|
||||
mappings = response.mappings();
|
||||
} catch (NullPointerException e) {
|
||||
throw new IllegalArgumentException("Not found the mapping info of index: " + index);
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
mappingMetaData = mappings.get(index);
|
||||
|
||||
return mappingMetaData;
|
||||
}
|
||||
|
||||
public class ES8xIndexRequest implements ESBulkRequest.ESIndexRequest {
|
||||
|
||||
private IndexRequestBuilder indexRequestBuilder;
|
||||
|
||||
private IndexRequest indexRequest;
|
||||
|
||||
public ES8xIndexRequest(String index, String id){
|
||||
indexRequest = new IndexRequest(index);
|
||||
indexRequest.id(id);
|
||||
|
||||
}
|
||||
|
||||
public ES8xIndexRequest setSource(Map<String, ?> source) {
|
||||
|
||||
indexRequest.source(source);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ES8xIndexRequest setRouting(String routing) {
|
||||
|
||||
indexRequest.routing(routing);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndexRequestBuilder getIndexRequestBuilder() {
|
||||
return indexRequestBuilder;
|
||||
}
|
||||
|
||||
public void setIndexRequestBuilder(IndexRequestBuilder indexRequestBuilder) {
|
||||
this.indexRequestBuilder = indexRequestBuilder;
|
||||
}
|
||||
|
||||
public IndexRequest getIndexRequest() {
|
||||
return indexRequest;
|
||||
}
|
||||
|
||||
public void setIndexRequest(IndexRequest indexRequest) {
|
||||
this.indexRequest = indexRequest;
|
||||
}
|
||||
}
|
||||
|
||||
public class ES8xUpdateRequest implements ESBulkRequest.ESUpdateRequest {
|
||||
|
||||
private UpdateRequestBuilder updateRequestBuilder;
|
||||
|
||||
private UpdateRequest updateRequest;
|
||||
|
||||
public ES8xUpdateRequest(String index, String id){
|
||||
|
||||
updateRequest = new UpdateRequest(index, id);
|
||||
}
|
||||
|
||||
public ES8xUpdateRequest setDoc(Map source) {
|
||||
|
||||
updateRequest.doc(source);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ES8xUpdateRequest setDocAsUpsert(boolean shouldUpsertDoc) {
|
||||
|
||||
updateRequest.docAsUpsert(shouldUpsertDoc);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ES8xUpdateRequest setRouting(String routing) {
|
||||
|
||||
updateRequest.routing(routing);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateRequestBuilder getUpdateRequestBuilder() {
|
||||
return updateRequestBuilder;
|
||||
}
|
||||
|
||||
public void setUpdateRequestBuilder(UpdateRequestBuilder updateRequestBuilder) {
|
||||
this.updateRequestBuilder = updateRequestBuilder;
|
||||
}
|
||||
|
||||
public UpdateRequest getUpdateRequest() {
|
||||
return updateRequest;
|
||||
}
|
||||
|
||||
public void setUpdateRequest(UpdateRequest updateRequest) {
|
||||
this.updateRequest = updateRequest;
|
||||
}
|
||||
}
|
||||
|
||||
public class ES8xDeleteRequest implements ESBulkRequest.ESDeleteRequest {
|
||||
|
||||
private DeleteRequestBuilder deleteRequestBuilder;
|
||||
|
||||
private DeleteRequest deleteRequest;
|
||||
|
||||
public ES8xDeleteRequest(String index, String id){
|
||||
|
||||
deleteRequest = new DeleteRequest(index, id);
|
||||
|
||||
}
|
||||
|
||||
public DeleteRequestBuilder getDeleteRequestBuilder() {
|
||||
return deleteRequestBuilder;
|
||||
}
|
||||
|
||||
public void setDeleteRequestBuilder(DeleteRequestBuilder deleteRequestBuilder) {
|
||||
this.deleteRequestBuilder = deleteRequestBuilder;
|
||||
}
|
||||
|
||||
public DeleteRequest getDeleteRequest() {
|
||||
return deleteRequest;
|
||||
}
|
||||
|
||||
public void setDeleteRequest(DeleteRequest deleteRequest) {
|
||||
this.deleteRequest = deleteRequest;
|
||||
}
|
||||
}
|
||||
|
||||
public class ESSearchRequest {
|
||||
|
||||
private SearchRequestBuilder searchRequestBuilder;
|
||||
|
||||
private SearchRequest searchRequest;
|
||||
|
||||
private SearchSourceBuilder sourceBuilder;
|
||||
|
||||
public ESSearchRequest(String index){
|
||||
|
||||
searchRequest = new SearchRequest(index);
|
||||
sourceBuilder = new SearchSourceBuilder();
|
||||
|
||||
}
|
||||
|
||||
public ESSearchRequest setQuery(QueryBuilder queryBuilder) {
|
||||
|
||||
sourceBuilder.query(queryBuilder);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ESSearchRequest size(int size) {
|
||||
|
||||
sourceBuilder.size(size);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchResponse getResponse() {
|
||||
|
||||
searchRequest.source(sourceBuilder);
|
||||
try {
|
||||
return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public SearchRequestBuilder getSearchRequestBuilder() {
|
||||
return searchRequestBuilder;
|
||||
}
|
||||
|
||||
public void setSearchRequestBuilder(SearchRequestBuilder searchRequestBuilder) {
|
||||
this.searchRequestBuilder = searchRequestBuilder;
|
||||
}
|
||||
|
||||
public SearchRequest getSearchRequest() {
|
||||
return searchRequest;
|
||||
}
|
||||
|
||||
public void setSearchRequest(SearchRequest searchRequest) {
|
||||
this.searchRequest = searchRequest;
|
||||
}
|
||||
}
|
||||
|
||||
public class ES8xBulkRequest implements ESBulkRequest {
|
||||
|
||||
private BulkRequestBuilder bulkRequestBuilder;
|
||||
|
||||
private BulkRequest bulkRequest;
|
||||
|
||||
public ES8xBulkRequest(){
|
||||
|
||||
bulkRequest = new BulkRequest();
|
||||
|
||||
}
|
||||
|
||||
public void resetBulk() {
|
||||
|
||||
bulkRequest = new BulkRequest();
|
||||
|
||||
}
|
||||
|
||||
public ES8xBulkRequest add(ESIndexRequest esIndexRequest) {
|
||||
ES8xIndexRequest eir = (ES8xIndexRequest) esIndexRequest;
|
||||
|
||||
bulkRequest.add(eir.indexRequest);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ES8xBulkRequest add(ESUpdateRequest esUpdateRequest) {
|
||||
ES8xUpdateRequest eur = (ES8xUpdateRequest) esUpdateRequest;
|
||||
|
||||
bulkRequest.add(eur.updateRequest);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ES8xBulkRequest add(ESDeleteRequest esDeleteRequest) {
|
||||
ES8xDeleteRequest edr = (ES8xDeleteRequest) esDeleteRequest;
|
||||
|
||||
bulkRequest.add(edr.deleteRequest);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int numberOfActions() {
|
||||
return bulkRequest.numberOfActions();
|
||||
}
|
||||
|
||||
public ESBulkResponse bulk() {
|
||||
try {
|
||||
BulkResponse responses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
|
||||
return new ES8xBulkResponse(responses);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public BulkRequestBuilder getBulkRequestBuilder() {
|
||||
return bulkRequestBuilder;
|
||||
}
|
||||
|
||||
public void setBulkRequestBuilder(BulkRequestBuilder bulkRequestBuilder) {
|
||||
this.bulkRequestBuilder = bulkRequestBuilder;
|
||||
}
|
||||
|
||||
public BulkRequest getBulkRequest() {
|
||||
return bulkRequest;
|
||||
}
|
||||
|
||||
public void setBulkRequest(BulkRequest bulkRequest) {
|
||||
this.bulkRequest = bulkRequest;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ES8xBulkResponse implements ESBulkRequest.ESBulkResponse {
|
||||
|
||||
private BulkResponse bulkResponse;
|
||||
|
||||
public ES8xBulkResponse(BulkResponse bulkResponse){
|
||||
this.bulkResponse = bulkResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFailures() {
|
||||
return bulkResponse.hasFailures();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processFailBulkResponse(String errorMsg) {
|
||||
for (BulkItemResponse itemResponse : bulkResponse.getItems()) {
|
||||
if (!itemResponse.isFailed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (itemResponse.getFailure().getStatus() == RestStatus.NOT_FOUND) {
|
||||
logger.error(itemResponse.getFailureMessage());
|
||||
} else {
|
||||
throw new RuntimeException(errorMsg + itemResponse.getFailureMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RestHighLevelClient getRestHighLevelClient() {
|
||||
return restHighLevelClient;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
es8=com.alibaba.otter.canal.client.adapter.es8x.ES8xAdapter
|
||||
20
client-adapter/es8x/src/main/resources/es8/biz_order.yml
Normal file
20
client-adapter/es8x/src/main/resources/es8/biz_order.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
dataSourceKey: defaultDS
|
||||
destination: example
|
||||
groupId: g1
|
||||
esMapping:
|
||||
_index: customer
|
||||
_id: _id
|
||||
relations:
|
||||
customer_order:
|
||||
name: order
|
||||
parent: customer_id
|
||||
sql: "select concat('oid_', t.id) as _id,
|
||||
t.customer_id,
|
||||
t.id as order_id,
|
||||
t.serial_code as order_serial,
|
||||
t.c_time as order_time
|
||||
from biz_order t"
|
||||
skips:
|
||||
- customer_id
|
||||
etlCondition: "where t.c_time>={}"
|
||||
commitBatch: 3000
|
||||
46
client-adapter/es8x/src/main/resources/es8/customer.yml
Normal file
46
client-adapter/es8x/src/main/resources/es8/customer.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
dataSourceKey: defaultDS
|
||||
destination: example
|
||||
groupId: g1
|
||||
esMapping:
|
||||
_index: customer
|
||||
_id: id
|
||||
relations:
|
||||
customer_order:
|
||||
name: customer
|
||||
sql: "select t.id, t.name, t.email from customer t"
|
||||
etlCondition: "where t.c_time>={}"
|
||||
commitBatch: 3000
|
||||
|
||||
|
||||
#{
|
||||
# "mappings":{
|
||||
# "_doc":{
|
||||
# "properties":{
|
||||
# "id": {
|
||||
# "type": "long"
|
||||
# },
|
||||
# "name": {
|
||||
# "type": "text"
|
||||
# },
|
||||
# "email": {
|
||||
# "type": "text"
|
||||
# },
|
||||
# "order_id": {
|
||||
# "type": "long"
|
||||
# },
|
||||
# "order_serial": {
|
||||
# "type": "text"
|
||||
# },
|
||||
# "order_time": {
|
||||
# "type": "date"
|
||||
# },
|
||||
# "customer_order":{
|
||||
# "type":"join",
|
||||
# "relations":{
|
||||
# "customer":"order"
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#}
|
||||
15
client-adapter/es8x/src/main/resources/es8/mytest_user.yml
Normal file
15
client-adapter/es8x/src/main/resources/es8/mytest_user.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
dataSourceKey: defaultDS
|
||||
destination: example
|
||||
groupId: g1
|
||||
esMapping:
|
||||
_index: mytest_user
|
||||
_id: _id
|
||||
# upsert: true
|
||||
# pk: id
|
||||
sql: "select a.id as _id, a.name, a.role_id, b.role_name,
|
||||
a.c_time from user a
|
||||
left join role b on b.id=a.role_id"
|
||||
# objFields:
|
||||
# _labels: array:;
|
||||
etlCondition: "where a.c_time>={}"
|
||||
commitBatch: 3000
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.alibaba.otter.canal.client.adapter.es8x.test;
|
||||
|
||||
import com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection;
|
||||
import org.elasticsearch.cluster.metadata.MappingMetadata;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Ignore
|
||||
public class ESConnectionTest {
|
||||
|
||||
ESConnection esConnection;
|
||||
|
||||
@Before
|
||||
public void init() throws UnknownHostException {
|
||||
String[] hosts = new String[]{"127.0.0.1:9200"};
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("cluster.name", "elasticsearch");
|
||||
esConnection = new ESConnection(hosts, properties);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test01() {
|
||||
MappingMetadata mappingMetaData = esConnection.getMapping("mytest_user");
|
||||
|
||||
Map<String, Object> sourceMap = mappingMetaData.getSourceAsMap();
|
||||
Map<String, Object> esMapping = (Map<String, Object>) sourceMap.get("properties");
|
||||
for (Map.Entry<String, Object> entry : esMapping.entrySet()) {
|
||||
Map<String, Object> value = (Map<String, Object>) entry.getValue();
|
||||
if (value.containsKey("properties")) {
|
||||
System.out.println(entry.getKey() + " object");
|
||||
} else {
|
||||
System.out.println(entry.getKey() + " " + value.get("type"));
|
||||
Assert.notNull(entry.getKey(), "null column name");
|
||||
Assert.notNull(value.get("type"), "null column type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.alibaba.otter.canal.client.adapter.es8x.test;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class TestConstant {
|
||||
|
||||
public final static String jdbcUrl = "jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true";
|
||||
public final static String jdbcUser = "root";
|
||||
public final static String jdbcPassword = "121212";
|
||||
|
||||
public final static String esHosts = "127.0.0.1:9300";
|
||||
public final static String clusterName = "elasticsearch";
|
||||
|
||||
public final static DruidDataSource dataSource;
|
||||
|
||||
static {
|
||||
dataSource = new DruidDataSource();
|
||||
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
|
||||
dataSource.setUrl(jdbcUrl);
|
||||
dataSource.setUsername(jdbcUser);
|
||||
dataSource.setPassword(jdbcPassword);
|
||||
dataSource.setInitialSize(1);
|
||||
dataSource.setMinIdle(1);
|
||||
dataSource.setMaxActive(1);
|
||||
dataSource.setMaxWait(60000);
|
||||
dataSource.setTimeBetweenEvictionRunsMillis(60000);
|
||||
dataSource.setMinEvictableIdleTimeMillis(300000);
|
||||
dataSource.setPoolPreparedStatements(false);
|
||||
dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
|
||||
dataSource.setValidationQuery("select 1");
|
||||
try {
|
||||
dataSource.init();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.otter.canal.client.adapter.support.AdapterConfig;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
/**
|
||||
* ES 映射配置
|
||||
@@ -28,13 +29,13 @@ public class ESSyncConfig implements AdapterConfig {
|
||||
private String esVersion = "es6";
|
||||
|
||||
public void validate() {
|
||||
if (esMapping._index == null) {
|
||||
if (esMapping.index == null) {
|
||||
throw new NullPointerException("esMapping._index");
|
||||
}
|
||||
if ("es6".equals(esVersion) && esMapping._type == null) {
|
||||
if ("es6".equals(esVersion) && esMapping.type == null) {
|
||||
throw new NullPointerException("esMapping._type");
|
||||
}
|
||||
if (esMapping._id == null && esMapping.getPk() == null) {
|
||||
if (esMapping.id == null && esMapping.getPk() == null) {
|
||||
throw new NullPointerException("esMapping._id or esMapping.pk");
|
||||
}
|
||||
if (esMapping.sql == null) {
|
||||
@@ -96,9 +97,14 @@ public class ESSyncConfig implements AdapterConfig {
|
||||
|
||||
public static class ESMapping implements AdapterMapping {
|
||||
|
||||
private String _index;
|
||||
private String _type;
|
||||
private String _id;
|
||||
@Value("${_index}")
|
||||
private String index;
|
||||
|
||||
@Value("${_type}")
|
||||
private String type;
|
||||
|
||||
@Value("${_id}")
|
||||
private String id;
|
||||
private boolean upsert = false;
|
||||
private String pk;
|
||||
private Map<String, RelationMapping> relations = new LinkedHashMap<>();
|
||||
@@ -114,28 +120,28 @@ public class ESSyncConfig implements AdapterConfig {
|
||||
|
||||
private SchemaItem schemaItem; // sql解析结果模型
|
||||
|
||||
public String get_index() {
|
||||
return _index;
|
||||
public String getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void set_index(String _index) {
|
||||
this._index = _index;
|
||||
public void setIndex(String index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public String get_type() {
|
||||
return _type;
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void set_type(String _type) {
|
||||
this._type = _type;
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String get_id() {
|
||||
return _id;
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void set_id(String _id) {
|
||||
this._id = _id;
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean isUpsert() {
|
||||
|
||||
@@ -136,8 +136,8 @@ public class SchemaItem {
|
||||
}
|
||||
|
||||
public FieldItem getIdFieldItem(ESSyncConfig.ESMapping mapping) {
|
||||
if (mapping.get_id() != null) {
|
||||
return getSelectFields().get(mapping.get_id());
|
||||
if (mapping.getId() != null) {
|
||||
return getSelectFields().get(mapping.getId());
|
||||
} else {
|
||||
return getSelectFields().get(mapping.getPk());
|
||||
}
|
||||
|
||||
@@ -54,13 +54,13 @@ public class ESSyncService {
|
||||
for (ESSyncConfig config : esSyncConfigs) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Prepared to sync index: {}, destination: {}",
|
||||
config.getEsMapping().get_index(),
|
||||
config.getEsMapping().getIndex(),
|
||||
dml.getDestination());
|
||||
}
|
||||
this.sync(config, dml);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Sync completed: {}, destination: {}",
|
||||
config.getEsMapping().get_index(),
|
||||
config.getEsMapping().getIndex(),
|
||||
dml.getDestination());
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ public class ESSyncService {
|
||||
if (logger.isDebugEnabled()) {
|
||||
StringBuilder configIndexes = new StringBuilder();
|
||||
esSyncConfigs
|
||||
.forEach(esSyncConfig -> configIndexes.append(esSyncConfig.getEsMapping().get_index()).append(" "));
|
||||
.forEach(esSyncConfig -> configIndexes.append(esSyncConfig.getEsMapping().getIndex()).append(" "));
|
||||
logger.debug("DML: {} \nAffected indexes: {}",
|
||||
JSON.toJSONString(dml, JSONWriter.Feature.WriteNulls),
|
||||
configIndexes.toString());
|
||||
@@ -105,10 +105,10 @@ public class ESSyncService {
|
||||
logger.trace("Sync elapsed time: {} ms,destination: {}, es index: {}",
|
||||
(System.currentTimeMillis() - begin),
|
||||
dml.getDestination(),
|
||||
config.getEsMapping().get_index());
|
||||
config.getEsMapping().getIndex());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("sync error, es index: {}, DML : {}", config.getEsMapping().get_index(), dml);
|
||||
logger.error("sync error, es index: {}, DML : {}", config.getEsMapping().getIndex(), dml);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@@ -210,7 +210,7 @@ public class ESSyncService {
|
||||
// ------主表 查询sql来更新------
|
||||
if (schemaItem.getMainTable().getTableName().equalsIgnoreCase(dml.getTable())) {
|
||||
ESMapping mapping = config.getEsMapping();
|
||||
String idFieldName = mapping.get_id() == null ? mapping.getPk() : mapping.get_id();
|
||||
String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();
|
||||
FieldItem idFieldItem = schemaItem.getSelectFields().get(idFieldName);
|
||||
|
||||
boolean idFieldSimple = true;
|
||||
@@ -336,7 +336,7 @@ public class ESSyncService {
|
||||
|
||||
// ------是主表------
|
||||
if (schemaItem.getMainTable().getTableName().equalsIgnoreCase(dml.getTable())) {
|
||||
if (mapping.get_id() != null) {
|
||||
if (mapping.getId() != null) {
|
||||
FieldItem idFieldItem = schemaItem.getIdFieldItem(mapping);
|
||||
// 主键为简单字段
|
||||
if (!idFieldItem.isMethod() && !idFieldItem.isBinaryOp()) {
|
||||
@@ -349,7 +349,7 @@ public class ESSyncService {
|
||||
logger.trace("Main table delete es index, destination:{}, table: {}, index: {}, id: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
idVal);
|
||||
}
|
||||
esTemplate.delete(mapping, idVal, null);
|
||||
@@ -368,7 +368,7 @@ public class ESSyncService {
|
||||
logger.trace("Main table delete es index, destination:{}, table: {}, index: {}, pk: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
pkVal);
|
||||
}
|
||||
esFieldData.remove(pkFieldItem.getFieldName());
|
||||
@@ -438,7 +438,7 @@ public class ESSyncService {
|
||||
logger.trace("Single table insert to es index, destination:{}, table: {}, index: {}, id: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
idVal);
|
||||
}
|
||||
esTemplate.insert(mapping, idVal, esFieldData);
|
||||
@@ -461,7 +461,7 @@ public class ESSyncService {
|
||||
logger.trace("Main table insert to es index by query sql, destination:{}, table: {}, index: {}, sql: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
sql.replace("\n", " "));
|
||||
}
|
||||
Util.sqlRS(ds, sql, rs -> {
|
||||
@@ -475,7 +475,7 @@ public class ESSyncService {
|
||||
"Main table insert to es index by query sql, destination:{}, table: {}, index: {}, id: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
idVal);
|
||||
}
|
||||
esTemplate.insert(mapping, idVal, esFieldData);
|
||||
@@ -497,7 +497,7 @@ public class ESSyncService {
|
||||
logger.trace("Main table delete es index by query sql, destination:{}, table: {}, index: {}, sql: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
sql.replace("\n", " "));
|
||||
}
|
||||
Util.sqlRS(ds, sql, rs -> {
|
||||
@@ -519,7 +519,7 @@ public class ESSyncService {
|
||||
"Main table delete to es index by query sql, destination:{}, table: {}, index: {}, id: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
idVal);
|
||||
}
|
||||
esTemplate.delete(mapping, idVal, esFieldData);
|
||||
@@ -554,7 +554,7 @@ public class ESSyncService {
|
||||
|
||||
String fieldName = fieldItem.getFieldName();
|
||||
// 判断是否是主键
|
||||
if (fieldName.equals(mapping.get_id())) {
|
||||
if (fieldName.equals(mapping.getId())) {
|
||||
fieldName = "_id";
|
||||
}
|
||||
paramsTmp.put(fieldName, value);
|
||||
@@ -566,7 +566,7 @@ public class ESSyncService {
|
||||
logger.trace("Join table update es index by foreign key, destination:{}, table: {}, index: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index());
|
||||
mapping.getIndex());
|
||||
}
|
||||
esTemplate.updateByQuery(config, paramsTmp, esFieldData);
|
||||
}
|
||||
@@ -617,7 +617,7 @@ public class ESSyncService {
|
||||
logger.trace("Join table update es index by query sql, destination:{}, table: {}, index: {}, sql: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
sql.toString().replace("\n", " "));
|
||||
}
|
||||
Util.sqlRS(ds, sql.toString(), values, rs -> {
|
||||
@@ -661,7 +661,7 @@ public class ESSyncService {
|
||||
entry.getKey().getColumn().getColumnName());
|
||||
String fieldName = fieldItem.getFieldName();
|
||||
// 判断是否是主键
|
||||
if (fieldName.equals(mapping.get_id())) {
|
||||
if (fieldName.equals(mapping.getId())) {
|
||||
fieldName = "_id";
|
||||
}
|
||||
paramsTmp.put(fieldName, value);
|
||||
@@ -673,7 +673,7 @@ public class ESSyncService {
|
||||
logger.trace("Join table update es index by query sql, destination:{}, table: {}, index: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index());
|
||||
mapping.getIndex());
|
||||
}
|
||||
esTemplate.updateByQuery(config, paramsTmp, esFieldData);
|
||||
}
|
||||
@@ -721,7 +721,7 @@ public class ESSyncService {
|
||||
logger.trace("Join table update es index by query whole sql, destination:{}, table: {}, index: {}, sql: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
sql.toString().replace("\n", " "));
|
||||
}
|
||||
Util.sqlRS(ds, sql.toString(), rs -> {
|
||||
@@ -775,7 +775,7 @@ public class ESSyncService {
|
||||
.getValFromRS(mapping, rs, fieldItem.getFieldName(), fieldItem.getFieldName());
|
||||
String fieldName = fieldItem.getFieldName();
|
||||
// 判断是否是主键
|
||||
if (fieldName.equals(mapping.get_id())) {
|
||||
if (fieldName.equals(mapping.getId())) {
|
||||
fieldName = "_id";
|
||||
}
|
||||
paramsTmp.put(fieldName, value);
|
||||
@@ -787,7 +787,7 @@ public class ESSyncService {
|
||||
"Join table update es index by query whole sql, destination:{}, table: {}, index: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index());
|
||||
mapping.getIndex());
|
||||
}
|
||||
esTemplate.updateByQuery(config, paramsTmp, esFieldData);
|
||||
}
|
||||
@@ -817,7 +817,7 @@ public class ESSyncService {
|
||||
logger.trace("Main table update to es index, destination:{}, table: {}, index: {}, id: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
idVal);
|
||||
}
|
||||
esTemplate.update(mapping, idVal, esFieldData);
|
||||
@@ -840,7 +840,7 @@ public class ESSyncService {
|
||||
logger.trace("Main table update to es index by query sql, destination:{}, table: {}, index: {}, sql: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
sql.replace("\n", " "));
|
||||
}
|
||||
Util.sqlRS(ds, sql, rs -> {
|
||||
@@ -854,7 +854,7 @@ public class ESSyncService {
|
||||
"Main table update to es index by query sql, destination:{}, table: {}, index: {}, id: {}",
|
||||
config.getDestination(),
|
||||
dml.getTable(),
|
||||
mapping.get_index(),
|
||||
mapping.getIndex(),
|
||||
idVal);
|
||||
}
|
||||
esTemplate.update(mapping, idVal, esFieldData);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -21,7 +21,6 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.hbase</groupId>
|
||||
<artifactId>hbase-shaded-client</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -21,18 +21,15 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.kudu</groupId>
|
||||
<artifactId>kudu-client</artifactId>
|
||||
<version>1.6.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.48</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>2.0.1.RELEASE</version>
|
||||
<version>2.5.4</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -128,6 +128,19 @@
|
||||
<classifier>jar-with-dependencies</classifier>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>client-adapter.es8x</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>*</artifactId>
|
||||
<groupId>*</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<classifier>jar-with-dependencies</classifier>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>client-adapter.rdb</artifactId>
|
||||
|
||||
@@ -43,6 +43,13 @@
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>../es8x/src/main/resources/es8</directory>
|
||||
<outputDirectory>/conf/es8</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>../hbase/src/main/resources/hbase</directory>
|
||||
<outputDirectory>/conf/hbase</outputDirectory>
|
||||
|
||||
@@ -44,6 +44,13 @@
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>../es8x/src/main/resources/es8</directory>
|
||||
<outputDirectory>/conf/es8</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>../hbase/src/main/resources/hbase</directory>
|
||||
<outputDirectory>/conf/hbase</outputDirectory>
|
||||
|
||||
@@ -59,7 +59,7 @@ esac
|
||||
JavaVersion=`$JAVA -version 2>&1 |awk 'NR==1{ gsub(/"/,""); print $3 }' | awk -F '.' '{print $1}'`
|
||||
str=`file -L $JAVA | grep 64-bit`
|
||||
|
||||
JAVA_OPTS="$JAVA_OPTS -Xss256k -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs"
|
||||
JAVA_OPTS="$JAVA_OPTS -Xss1m -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs"
|
||||
if [ $JavaVersion -ge 11 ] ; then
|
||||
#JAVA_OPTS="$JAVA_OPTS -Xlog:gc*:$base_log/gc.log:time "
|
||||
JAVA_OPTS="$JAVA_OPTS"
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.alibaba.otter.canal.adapter.launcher;
|
||||
import org.springframework.boot.Banner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
|
||||
/**
|
||||
* 启动入口
|
||||
@@ -10,7 +11,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
* @author rewerma @ 2018-10-20
|
||||
* @version 1.0.0
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(exclude= { DataSourceAutoConfiguration.class})
|
||||
public class CanalAdapterApplication {
|
||||
public static void main(String[] args) {
|
||||
// 支持rocketmq client 配置日志路径
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.alibaba.otter.canal.adapter.launcher.loader;
|
||||
|
||||
import com.alibaba.otter.canal.connector.core.spi.ProxyCanalMsgConsumer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
@@ -8,7 +7,6 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -24,6 +22,7 @@ import com.alibaba.otter.canal.connector.core.config.CanalConstants;
|
||||
import com.alibaba.otter.canal.connector.core.consumer.CommonMessage;
|
||||
import com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer;
|
||||
import com.alibaba.otter.canal.connector.core.spi.ExtensionLoader;
|
||||
import com.alibaba.otter.canal.connector.core.spi.ProxyCanalMsgConsumer;
|
||||
|
||||
/**
|
||||
* 适配处理器
|
||||
@@ -87,6 +86,7 @@ public class AdapterProcessor {
|
||||
public void writeOut(final List<CommonMessage> commonMessages) {
|
||||
List<Future<Boolean>> futures = new ArrayList<>();
|
||||
// 组间适配器并行运行
|
||||
// 当 canalOuterAdapters 初始化失败时,消息将会全部丢失
|
||||
canalOuterAdapters.forEach(outerAdapters -> {
|
||||
futures.add(groupInnerExecutorService.submit(() -> {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.alibaba.otter.canal.adapter.launcher.loader;
|
||||
|
||||
import com.alibaba.otter.canal.client.adapter.ProxyOuterAdapter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -17,9 +16,11 @@ import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.alibaba.otter.canal.adapter.launcher.config.SpringContext;
|
||||
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||
import com.alibaba.otter.canal.client.adapter.ProxyOuterAdapter;
|
||||
import com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.support.ExtensionLoader;
|
||||
import com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;
|
||||
@@ -70,7 +71,13 @@ public class CanalAdapterLoader {
|
||||
loadAdapter(config, canalOuterAdapters);
|
||||
}
|
||||
canalOuterAdapterGroups.add(canalOuterAdapters);
|
||||
|
||||
// canalOuterAdapters 存在初始化失败的情况,导致canalOuterAdapters的数量,可能小于group.getOuterAdapters
|
||||
// 由于group下的 所有OuterAdapter实例都会重复消费同一批消息,因此不允许部分adapter初始化成功,必须全部初始化成功才允许消费
|
||||
if(CollectionUtils.isEmpty(canalOuterAdapters) || canalOuterAdapters.size() != group.getOuterAdapters().size() ){
|
||||
String msg = String.format("instance=%s,groupId=%s Load OuterAdapters is Empty,pls check rdb.yml",
|
||||
canalAdapter.getInstance(),group.getGroupId());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
AdapterProcessor adapterProcessor = canalAdapterProcessors.computeIfAbsent(
|
||||
canalAdapter.getInstance() + "|" + StringUtils.trimToEmpty(group.getGroupId()),
|
||||
f -> new AdapterProcessor(canalClientConfig,
|
||||
@@ -78,7 +85,6 @@ public class CanalAdapterLoader {
|
||||
group.getGroupId(),
|
||||
canalOuterAdapterGroups));
|
||||
adapterProcessor.start();
|
||||
|
||||
logger.info("Start adapter for canal-client mq topic: {} succeed",
|
||||
canalAdapter.getInstance() + "-" + group.getGroupId());
|
||||
}
|
||||
@@ -107,6 +113,7 @@ public class CanalAdapterLoader {
|
||||
}
|
||||
}
|
||||
adapter.init(config, evnProperties);
|
||||
// rdb文件解析异常时,canalOuterAdapters 无法正常加载
|
||||
canalOutConnectors.add(adapter);
|
||||
logger.info("Load canal adapter: {} succeed", config.getName());
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -20,7 +20,6 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -17,13 +17,12 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.phoenix</groupId>
|
||||
<artifactId>phoenix-core</artifactId>
|
||||
<version>4.14.1-HBase-1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.hbase</groupId>
|
||||
<artifactId>hbase-client</artifactId>
|
||||
<version>1.4.8</version>
|
||||
</dependency>
|
||||
<!-- 强制指定protobuf版本 -->
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
@@ -71,7 +70,6 @@
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
package com.alibaba.otter.canal.client.adapter.phoenix.service;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.otter.canal.client.adapter.phoenix.PhoenixAdapter;
|
||||
import com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig.DbMapping;
|
||||
@@ -10,16 +22,6 @@ import com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.support.EtlResult;
|
||||
import com.alibaba.otter.canal.client.adapter.support.Util;
|
||||
import com.google.common.base.Joiner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Phoenix ETL 操作业务类
|
||||
@@ -41,16 +43,17 @@ public class PhoenixEtlService {
|
||||
if (srcDataSource == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return syncSchema(srcDataSource.getConnection(), targetDSConnection, config);
|
||||
|
||||
try (Connection conn = srcDataSource.getConnection()) {
|
||||
return syncSchema(conn, targetDSConnection, config);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean syncSchema(DataSource srcDS,Connection targetDSConnection, MappingConfig config) {
|
||||
try {
|
||||
return syncSchema(srcDS.getConnection(),targetDSConnection, config);
|
||||
try (Connection conn = srcDS.getConnection()) {
|
||||
return syncSchema(conn, targetDSConnection, config);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>canal client adapter module for otter ${project.version}</name>
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<module>rdb</module>
|
||||
<module>es6x</module>
|
||||
<module>es7x</module>
|
||||
<module>es8x</module>
|
||||
<module>escore</module>
|
||||
<module>kudu</module>
|
||||
<module>phoenix</module>
|
||||
@@ -110,12 +111,12 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
<version>2.0.0.RELEASE</version>
|
||||
<version>3.0.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
<version>2.0.1.RELEASE</version>
|
||||
<version>2.5.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
@@ -126,35 +127,35 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-client</artifactId>
|
||||
<version>4.5.1</version>
|
||||
<version>${rocketmq_version}</version>
|
||||
</dependency>
|
||||
<!-- 单独引入kafka依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka-clients</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>${kafka_version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- rabbotmq -->
|
||||
<dependency>
|
||||
<groupId>com.rabbitmq</groupId>
|
||||
<artifactId>amqp-client</artifactId>
|
||||
<version>5.5.0</version>
|
||||
<version>${rabbitmq_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.mq-amqp</groupId>
|
||||
<artifactId>mq-amqp-client</artifactId>
|
||||
<version>1.0.3</version>
|
||||
<version>${mq_amqp_client}</version>
|
||||
</dependency>
|
||||
<!-- jdbc -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.48</version>
|
||||
<version>${mysql_driver_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.1.4</version>
|
||||
<version>42.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
@@ -166,7 +167,6 @@
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<version>7.0.0.jre8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.hbase</groupId>
|
||||
<artifactId>hbase-shaded-client</artifactId>
|
||||
@@ -182,6 +182,37 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.phoenix</groupId>
|
||||
<artifactId>phoenix-core</artifactId>
|
||||
<version>4.14.1-HBase-1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.hbase</groupId>
|
||||
<artifactId>hbase-client</artifactId>
|
||||
<version>1.4.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun.openservices</groupId>
|
||||
<artifactId>tablestore</artifactId>
|
||||
<version>5.10.3</version>
|
||||
<classifier>jar-with-dependencies</classifier>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpasyncclient</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.kudu</groupId>
|
||||
<artifactId>kudu-client</artifactId>
|
||||
<version>1.6.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-recipes</artifactId>
|
||||
@@ -201,8 +232,9 @@
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.19</version>
|
||||
<version>1.29</version>
|
||||
</dependency>
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
@@ -233,39 +265,6 @@
|
||||
<version>1.9.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun.openservices</groupId>
|
||||
<artifactId>tablestore</artifactId>
|
||||
<version>5.10.3</version>
|
||||
<classifier>jar-with-dependencies</classifier>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpasyncclient</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-to-slf4j</artifactId>
|
||||
<version>${log4j_version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -42,7 +42,6 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
package com.alibaba.otter.canal.client.adapter.rdb;
|
||||
|
||||
import com.alibaba.otter.canal.client.adapter.support.FileName2KeyMapping;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
@@ -27,11 +22,7 @@ import com.alibaba.otter.canal.client.adapter.rdb.service.RdbEtlService;
|
||||
import com.alibaba.otter.canal.client.adapter.rdb.service.RdbMirrorDbSyncService;
|
||||
import com.alibaba.otter.canal.client.adapter.rdb.service.RdbSyncService;
|
||||
import com.alibaba.otter.canal.client.adapter.rdb.support.SyncUtil;
|
||||
import com.alibaba.otter.canal.client.adapter.support.Dml;
|
||||
import com.alibaba.otter.canal.client.adapter.support.EtlResult;
|
||||
import com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;
|
||||
import com.alibaba.otter.canal.client.adapter.support.SPI;
|
||||
import com.alibaba.otter.canal.client.adapter.support.Util;
|
||||
import com.alibaba.otter.canal.client.adapter.support.*;
|
||||
|
||||
/**
|
||||
* RDB适配器实现类
|
||||
@@ -84,6 +75,7 @@ public class RdbAdapter implements OuterAdapter {
|
||||
// 从jdbc url获取db类型
|
||||
Map<String, String> properties = configuration.getProperties();
|
||||
String dbType = JdbcUtils.getDbType(properties.get("jdbc.url"), null);
|
||||
// 当.yml文件编码格式存在问题,此处rdb yml文件构建 可能会抛出异常
|
||||
Map<String, MappingConfig> rdbMappingTmp = ConfigLoader.load(envProperties);
|
||||
// 过滤不匹配的key的配置
|
||||
rdbMappingTmp.forEach((key, config) -> {
|
||||
|
||||
@@ -164,7 +164,8 @@ public class RdbMirrorDbSyncService {
|
||||
logger.trace("Execute DDL sql: {} for database: {}", ddl.getSql(), ddl.getDatabase());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
logger.error("Execute DDL sql failed sql: {} for database: {} cause: {}",
|
||||
ddl.getSql(), ddl.getDatabase(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,5 @@
|
||||
package com.alibaba.otter.canal.client.adapter.rdb.service;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONWriter.Feature;
|
||||
@@ -30,6 +10,27 @@ import com.alibaba.otter.canal.client.adapter.rdb.support.SingleDml;
|
||||
import com.alibaba.otter.canal.client.adapter.rdb.support.SyncUtil;
|
||||
import com.alibaba.otter.canal.client.adapter.support.Dml;
|
||||
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.sql.Connection;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* RDB同步操作业务
|
||||
@@ -272,7 +273,7 @@ public class RdbSyncService {
|
||||
len = insertSql.length();
|
||||
insertSql.delete(len - 1, len).append(")");
|
||||
|
||||
Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);
|
||||
Map<String, Integer> ctype = getTargetColumnTypeByColumns(batchExecutor.getConn(), config, columnsMap);
|
||||
|
||||
List<Map<String, ?>> values = new ArrayList<>();
|
||||
for (Map.Entry<String, String> entry : columnsMap.entrySet()) {
|
||||
@@ -328,7 +329,7 @@ public class RdbSyncService {
|
||||
String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());
|
||||
Map<String, String> columnsMap = SyncUtil.getColumnsMap(dbMapping, data);
|
||||
|
||||
Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);
|
||||
Map<String, Integer> ctype = getTargetColumnTypeByColumns(batchExecutor.getConn(), config, columnsMap);
|
||||
|
||||
StringBuilder updateSql = new StringBuilder();
|
||||
updateSql.append("UPDATE ").append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType())).append(" SET ");
|
||||
@@ -410,6 +411,57 @@ public class RdbSyncService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain metadata for the corresponding table columns of the target data source
|
||||
* Check if the metadata of the columns in the src is consistent with the metadata cache of the columns in the cache
|
||||
* (first determine the number of columns and then determine if each column is consistent).
|
||||
* If not, reload
|
||||
* @param conn
|
||||
* @param config
|
||||
* @param columnsMap
|
||||
* @date 2024/6/17 14:45
|
||||
*/
|
||||
private Map<String, Integer> getTargetColumnTypeByColumns(Connection conn, MappingConfig config,
|
||||
Map<String, String> columnsMap) {
|
||||
DbMapping dbMapping = config.getDbMapping();
|
||||
String cacheKey = config.getDestination() + "." + dbMapping.getDatabase() + "." + dbMapping.getTable();
|
||||
Map<String, Integer> columnType = getTargetColumnType(conn, config);
|
||||
if(null != columnType && null != columnsMap &&
|
||||
!checkCloumnConsistent(columnType.keySet(), columnsMap.keySet())){
|
||||
logger.info("column meta data not match, reload the column meta data from target db. key:{}", cacheKey);
|
||||
columnsTypeCache.remove(cacheKey);
|
||||
columnType = getTargetColumnType(conn, config);
|
||||
if(null != columnType && null != columnsMap &&
|
||||
!checkCloumnConsistent(columnType.keySet(), columnsMap.keySet())) {
|
||||
logger.info("the column meta data from db still not match. dbdata:{}", columnType.keySet());
|
||||
}
|
||||
}
|
||||
return columnType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断binlog的中的列的数据和缓存的列数据是否一致
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param column
|
||||
* @param anotherColumn
|
||||
* @return {@link Boolean}
|
||||
*/
|
||||
public static<T> Boolean checkCloumnConsistent(Collection<T> column, Collection<T> anotherColumn) {
|
||||
if(null == column || null == anotherColumn || column.size() != anotherColumn.size()){
|
||||
return false;
|
||||
}
|
||||
Map<T, T> anotherColumnMap = column.stream().collect(Collectors.toMap(Function.identity(), Function.identity()));
|
||||
|
||||
for (T t : column) {
|
||||
if(null == anotherColumnMap.get(t)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取目标字段类型
|
||||
*
|
||||
|
||||
@@ -26,7 +26,7 @@ public class SyncUtil {
|
||||
public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Collection<String> columns) {
|
||||
Map<String, String> columnsMap;
|
||||
if (dbMapping.getMapAll()) {
|
||||
if (dbMapping.getAllMapColumns() != null) {
|
||||
if (dbMapping.getAllMapColumns() != null && columns.size() == dbMapping.getAllMapColumns().size() ) {
|
||||
return dbMapping.getAllMapColumns();
|
||||
}
|
||||
columnsMap = new LinkedHashMap<>();
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<parent>
|
||||
<artifactId>canal.client-adapter</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>client-adapter.tablestore</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>canal client adapter rdb module for otter ${project.version}</name>
|
||||
<name>canal client adapter tablestore module for otter ${project.version}</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -30,7 +30,6 @@
|
||||
<dependency>
|
||||
<groupId>com.aliyun.openservices</groupId>
|
||||
<artifactId>tablestore</artifactId>
|
||||
<version>5.10.3</version>
|
||||
<classifier>jar-with-dependencies</classifier>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -43,8 +42,6 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
@@ -101,42 +101,44 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-client</artifactId>
|
||||
<version>4.5.2</version>
|
||||
<version>${rocketmq_version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-acl</artifactId>
|
||||
<version>4.5.2</version>
|
||||
<version>${rocketmq_version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.rabbitmq</groupId>
|
||||
<artifactId>amqp-client</artifactId>
|
||||
<version>5.5.0</version>
|
||||
<version>${rabbitmq_version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.mq-amqp</groupId>
|
||||
<artifactId>mq-amqp-client</artifactId>
|
||||
<version>1.0.3</version>
|
||||
<version>${mq_amqp_client}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka-clients</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>${kafka_version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Pulsar -->
|
||||
<dependency>
|
||||
<groupId>org.apache.pulsar</groupId>
|
||||
<artifactId>pulsar-client</artifactId>
|
||||
<version>${pulsar_version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pulsar</groupId>
|
||||
<artifactId>pulsar-client-admin</artifactId>
|
||||
<version>${pulsar_version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>canal.common</artifactId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka_2.11</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<artifactId>kafka-clients</artifactId>
|
||||
<version>${kafka_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@@ -89,4 +89,4 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>canal connector module for otter ${project.version}</name>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -35,10 +35,12 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.pulsar</groupId>
|
||||
<artifactId>pulsar-client</artifactId>
|
||||
<version>${pulsar_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pulsar</groupId>
|
||||
<artifactId>pulsar-client-admin</artifactId>
|
||||
<version>${pulsar_version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
<dependency>
|
||||
<groupId>com.rabbitmq</groupId>
|
||||
<artifactId>amqp-client</artifactId>
|
||||
<version>5.5.0</version>
|
||||
<version>${rabbitmq_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.mq-amqp</groupId>
|
||||
<artifactId>mq-amqp-client</artifactId>
|
||||
<version>1.0.3</version>
|
||||
<version>${mq_amqp_client}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@@ -94,4 +94,4 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -15,6 +15,9 @@ public class RabbitMQConstants {
|
||||
public static final String RABBITMQ_VIRTUAL_HOST = ROOT + "." + "virtual.host";
|
||||
public static final String RABBITMQ_USERNAME = ROOT + "." + "username";
|
||||
public static final String RABBITMQ_PASSWORD = ROOT + "." + "password";
|
||||
public static final String RABBITMQ_QUEUE = ROOT + "." + "queue";
|
||||
public static final String RABBITMQ_ROUTING_KEY = ROOT + "." + "routingKey";
|
||||
public static final String RABBITMQ_DELIVERY_MODE = ROOT + "." + "deliveryMode";
|
||||
|
||||
public static final String RABBITMQ_RESOURCE_OWNERID = ROOT + "." + "rabbitmq.resource.ownerId";
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ public class RabbitMQProducerConfig extends MQProperties {
|
||||
private String exchange;
|
||||
private String username;
|
||||
private String password;
|
||||
private String queue;
|
||||
private String routingKey;
|
||||
private String deliveryMode;
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
@@ -55,4 +58,28 @@ public class RabbitMQProducerConfig extends MQProperties {
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getQueue() {
|
||||
return queue;
|
||||
}
|
||||
|
||||
public void setQueue(String queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
public String getRoutingKey() {
|
||||
return routingKey;
|
||||
}
|
||||
|
||||
public void setRoutingKey(String routingKey) {
|
||||
this.routingKey = routingKey;
|
||||
}
|
||||
|
||||
public String getDeliveryMode() {
|
||||
return deliveryMode;
|
||||
}
|
||||
|
||||
public void setDeliveryMode(String deliveryMode) {
|
||||
this.deliveryMode = deliveryMode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ 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;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.otter.canal.common.utils.PropertiesUtils;
|
||||
import com.alibaba.otter.canal.connector.core.config.CanalConstants;
|
||||
import com.alibaba.otter.canal.connector.core.consumer.CommonMessage;
|
||||
import com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer;
|
||||
@@ -24,13 +24,7 @@ import com.alibaba.otter.canal.connector.rabbitmq.config.RabbitMQConstants;
|
||||
import com.alibaba.otter.canal.connector.rabbitmq.producer.AliyunCredentialsProvider;
|
||||
import com.alibaba.otter.canal.protocol.Message;
|
||||
import com.alibaba.otter.canal.protocol.exception.CanalClientException;
|
||||
import com.rabbitmq.client.AMQP;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
import com.rabbitmq.client.Consumer;
|
||||
import com.rabbitmq.client.DefaultConsumer;
|
||||
import com.rabbitmq.client.Envelope;
|
||||
import com.rabbitmq.client.*;
|
||||
|
||||
/**
|
||||
* RabbitMQ consumer SPI 实现
|
||||
@@ -41,7 +35,8 @@ import com.rabbitmq.client.Envelope;
|
||||
@SPI("rabbitmq")
|
||||
public class CanalRabbitMQConsumer implements CanalMsgConsumer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CanalRabbitMQConsumer.class);
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(CanalRabbitMQConsumer.class);
|
||||
|
||||
// 链接地址
|
||||
private String nameServer;
|
||||
@@ -91,7 +86,7 @@ public class CanalRabbitMQConsumer implements CanalMsgConsumer {
|
||||
factory.setUsername(username);
|
||||
factory.setPassword(password);
|
||||
}
|
||||
//解析出端口 modified by 16075140
|
||||
// 解析出端口 modified by 16075140
|
||||
if (nameServer != null && nameServer.contains(":")) {
|
||||
String[] serverHostAndPort = nameServer.split(":");
|
||||
factory.setHost(serverHostAndPort[0]);
|
||||
|
||||
@@ -26,10 +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;
|
||||
import com.rabbitmq.client.*;
|
||||
|
||||
/**
|
||||
* RabbitMQ Producer SPI 实现
|
||||
@@ -75,7 +72,24 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
try {
|
||||
connect = factory.newConnection();
|
||||
channel = connect.createChannel();
|
||||
// channel.exchangeDeclare(mqProperties.getExchange(), "topic");
|
||||
String queue=rabbitMQProperties.getQueue();
|
||||
String exchange=rabbitMQProperties.getExchange();
|
||||
String deliveryMode=rabbitMQProperties.getDeliveryMode();
|
||||
String routingKey=rabbitMQProperties.getRoutingKey();
|
||||
if(!StringUtils.isEmpty(queue))
|
||||
{
|
||||
channel.queueDeclare(queue, true, false, false, null);
|
||||
}
|
||||
if(!StringUtils.isEmpty(queue)
|
||||
&&!StringUtils.isEmpty(exchange)
|
||||
&&!StringUtils.isEmpty(deliveryMode)
|
||||
&&!StringUtils.isEmpty(routingKey))
|
||||
{
|
||||
channel.exchangeDeclare(exchange, deliveryMode, true, false, false, null);
|
||||
channel.queueBind(queue,exchange,routingKey);
|
||||
}
|
||||
|
||||
|
||||
} catch (IOException | TimeoutException ex) {
|
||||
throw new CanalException("Start RabbitMQ producer error", ex);
|
||||
}
|
||||
@@ -106,6 +120,18 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
if (!StringUtils.isEmpty(password)) {
|
||||
rabbitMQProperties.setPassword(password);
|
||||
}
|
||||
String queue = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_QUEUE);
|
||||
if (!StringUtils.isEmpty(queue)) {
|
||||
rabbitMQProperties.setQueue(queue);
|
||||
}
|
||||
String routingKey = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_ROUTING_KEY);
|
||||
if (!StringUtils.isEmpty(routingKey)) {
|
||||
rabbitMQProperties.setRoutingKey(routingKey);
|
||||
}
|
||||
String deliveryMode = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_DELIVERY_MODE);
|
||||
if (!StringUtils.isEmpty(deliveryMode)) {
|
||||
rabbitMQProperties.setDeliveryMode(deliveryMode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,9 +140,8 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
try {
|
||||
if (!StringUtils.isEmpty(destination.getDynamicTopic())) {
|
||||
// 动态topic
|
||||
Map<String, Message> messageMap = MQMessageUtils.messageTopics(message,
|
||||
destination.getTopic(),
|
||||
destination.getDynamicTopic());
|
||||
Map<String, Message> messageMap = MQMessageUtils
|
||||
.messageTopics(message, destination.getTopic(), destination.getDynamicTopic());
|
||||
|
||||
for (Map.Entry<String, com.alibaba.otter.canal.protocol.Message> entry : messageMap.entrySet()) {
|
||||
final String topicName = entry.getKey().replace('.', '_');
|
||||
@@ -165,7 +190,10 @@ public class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQ
|
||||
// tips: 目前逻辑中暂不处理对exchange处理,请在Console后台绑定 才可使用routekey
|
||||
try {
|
||||
RabbitMQProducerConfig rabbitMQProperties = (RabbitMQProducerConfig) this.mqProperties;
|
||||
channel.basicPublish(rabbitMQProperties.getExchange(), queueName, null, message);
|
||||
channel.basicPublish(rabbitMQProperties.getExchange(),
|
||||
queueName,
|
||||
MessageProperties.PERSISTENT_TEXT_PLAIN,
|
||||
message);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
<packaging>jar</packaging>
|
||||
<name>canal connector rocketMQ module for otter ${project.version}</name>
|
||||
|
||||
<properties>
|
||||
<rocketmq_version>4.8.0</rocketmq_version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
@@ -99,4 +95,4 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>canal.connector</artifactId>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
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 org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.alibaba.otter.canal.client.CanalConnector;
|
||||
import com.alibaba.otter.canal.client.impl.ClusterCanalConnector;
|
||||
import com.alibaba.otter.canal.client.impl.ClusterNodeAccessStrategy;
|
||||
@@ -12,14 +20,6 @@ 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实例
|
||||
*
|
||||
@@ -99,7 +99,9 @@ public class CanalTCPConsumer implements CanalMsgConsumer {
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
canalConnector.unsubscribe();
|
||||
// tcp模式下,因为是单tcp消费,避免adapter异常断开时直接unsubscribe
|
||||
// unsubscribe发送给canal-server会导致清理cursor位点,如果此时canal-server出现重启,就会丢失binlog数据
|
||||
// canalConnector.unsubscribe();
|
||||
canalConnector.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
@@ -33,6 +33,14 @@
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.luben</groupId>
|
||||
<artifactId>zstd-jni</artifactId>
|
||||
</dependency>
|
||||
<!-- test dependency -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.taobao.tddl.dbsync.binlog;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.Charset;
|
||||
@@ -10,6 +10,9 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.apache.commons.compress.compressors.deflate.DeflateCompressorInputStream;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
/**
|
||||
* TODO: Document Me!!
|
||||
*
|
||||
@@ -30,7 +33,9 @@ public class LogBuffer {
|
||||
}
|
||||
|
||||
public LogBuffer(byte[] buffer, final int origin, final int limit){
|
||||
if (origin + limit > buffer.length) throw new IllegalArgumentException("capacity excceed: " + (origin + limit));
|
||||
if (origin + limit > buffer.length) {
|
||||
throw new IllegalArgumentException("capacity excceed: " + (origin + limit));
|
||||
}
|
||||
|
||||
this.buffer = buffer;
|
||||
this.origin = origin;
|
||||
@@ -42,7 +47,9 @@ public class LogBuffer {
|
||||
* Return n bytes in this buffer.
|
||||
*/
|
||||
public final LogBuffer duplicate(final int pos, final int len) {
|
||||
if (pos + len > limit) throw new IllegalArgumentException("limit excceed: " + (pos + len));
|
||||
if (pos + len > limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos + len));
|
||||
}
|
||||
|
||||
// XXX: Do momery copy avoid buffer modified.
|
||||
final int off = origin + pos;
|
||||
@@ -54,8 +61,9 @@ public class LogBuffer {
|
||||
* Return next n bytes in this buffer.
|
||||
*/
|
||||
public final LogBuffer duplicate(final int len) {
|
||||
if (position + len > origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position + len - origin));
|
||||
if (position + len > origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
|
||||
}
|
||||
|
||||
// XXX: Do momery copy avoid buffer modified.
|
||||
final int end = position + len;
|
||||
@@ -103,7 +111,9 @@ public class LogBuffer {
|
||||
* <tt>newPosition</tt> do not hold
|
||||
*/
|
||||
public final LogBuffer position(final int newPosition) {
|
||||
if (newPosition > limit || newPosition < 0) throw new IllegalArgumentException("limit excceed: " + newPosition);
|
||||
if (newPosition > limit || newPosition < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + newPosition);
|
||||
}
|
||||
|
||||
this.position = origin + newPosition;
|
||||
return this;
|
||||
@@ -116,8 +126,9 @@ public class LogBuffer {
|
||||
* @return This buffer
|
||||
*/
|
||||
public final LogBuffer forward(final int len) {
|
||||
if (position + len > origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position + len - origin));
|
||||
if (position + len > origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
|
||||
}
|
||||
|
||||
this.position += len;
|
||||
return this;
|
||||
@@ -209,7 +220,9 @@ public class LogBuffer {
|
||||
* Return 8-bit signed int from buffer.
|
||||
*/
|
||||
public final int getInt8(final int pos) {
|
||||
if (pos >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: " + pos);
|
||||
if (pos >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + pos);
|
||||
}
|
||||
|
||||
return buffer[origin + pos];
|
||||
}
|
||||
@@ -218,7 +231,9 @@ public class LogBuffer {
|
||||
* Return next 8-bit signed int from buffer.
|
||||
*/
|
||||
public final int getInt8() {
|
||||
if (position >= origin + limit) throw new IllegalArgumentException("limit excceed: " + (position - origin));
|
||||
if (position >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin));
|
||||
}
|
||||
|
||||
return buffer[position++];
|
||||
}
|
||||
@@ -227,7 +242,9 @@ public class LogBuffer {
|
||||
* Return 8-bit unsigned int from buffer.
|
||||
*/
|
||||
public final int getUint8(final int pos) {
|
||||
if (pos >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: " + pos);
|
||||
if (pos >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + pos);
|
||||
}
|
||||
|
||||
return 0xff & buffer[origin + pos];
|
||||
}
|
||||
@@ -236,7 +253,9 @@ public class LogBuffer {
|
||||
* Return next 8-bit unsigned int from buffer.
|
||||
*/
|
||||
public final int getUint8() {
|
||||
if (position >= origin + limit) throw new IllegalArgumentException("limit excceed: " + (position - origin));
|
||||
if (position >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin));
|
||||
}
|
||||
|
||||
return 0xff & buffer[position++];
|
||||
}
|
||||
@@ -249,8 +268,9 @@ public class LogBuffer {
|
||||
public final int getInt16(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 1 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 1)));
|
||||
if (pos + 1 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 1)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position]) | ((buf[position + 1]) << 8);
|
||||
@@ -262,8 +282,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - sint2korr
|
||||
*/
|
||||
public final int getInt16() {
|
||||
if (position + 1 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 1));
|
||||
if (position + 1 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 1));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position++]) | ((buf[position++]) << 8);
|
||||
@@ -277,8 +298,9 @@ public class LogBuffer {
|
||||
public final int getUint16(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 1 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 1)));
|
||||
if (pos + 1 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 1)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8);
|
||||
@@ -290,8 +312,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - uint2korr
|
||||
*/
|
||||
public final int getUint16() {
|
||||
if (position + 1 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 1));
|
||||
if (position + 1 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 1));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8);
|
||||
@@ -304,9 +327,9 @@ public class LogBuffer {
|
||||
*/
|
||||
public final int getBeInt16(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 1 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 1)));
|
||||
if (pos + 1 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 1)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position + 1]) | ((buf[position]) << 8);
|
||||
@@ -318,8 +341,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - mi_sint2korr
|
||||
*/
|
||||
public final int getBeInt16() {
|
||||
if (position + 1 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 1));
|
||||
if (position + 1 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 1));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (buf[position++] << 8) | (0xff & buf[position++]);
|
||||
@@ -332,9 +356,9 @@ public class LogBuffer {
|
||||
*/
|
||||
public final int getBeUint16(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 1 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 1)));
|
||||
if (pos + 1 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 1)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position + 1]) | ((0xff & buf[position]) << 8);
|
||||
@@ -346,8 +370,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.6.10/include/myisampack.h - mi_usint2korr
|
||||
*/
|
||||
public final int getBeUint16() {
|
||||
if (position + 1 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 1));
|
||||
if (position + 1 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 1));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((0xff & buf[position++]) << 8) | (0xff & buf[position++]);
|
||||
@@ -361,8 +386,9 @@ public class LogBuffer {
|
||||
public final int getInt24(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 2 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 2)));
|
||||
if (pos + 2 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 2)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8) | ((buf[position + 2]) << 16);
|
||||
@@ -374,8 +400,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - sint3korr
|
||||
*/
|
||||
public final int getInt24() {
|
||||
if (position + 2 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 2));
|
||||
if (position + 2 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 2));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8) | ((buf[position++]) << 16);
|
||||
@@ -389,8 +416,9 @@ public class LogBuffer {
|
||||
public final int getBeInt24(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 2 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 2)));
|
||||
if (pos + 2 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 2)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position + 2]) | ((0xff & buf[position + 1]) << 8) | ((buf[position]) << 16);
|
||||
@@ -402,8 +430,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.6.10/include/myisampack.h - mi_usint3korr
|
||||
*/
|
||||
public final int getBeInt24() {
|
||||
if (position + 2 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 2));
|
||||
if (position + 2 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 2));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((buf[position++]) << 16) | ((0xff & buf[position++]) << 8) | (0xff & buf[position++]);
|
||||
@@ -417,8 +446,9 @@ public class LogBuffer {
|
||||
public final int getUint24(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 2 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 2)));
|
||||
if (pos + 2 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 2)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8) | ((0xff & buf[position + 2]) << 16);
|
||||
@@ -430,8 +460,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - uint3korr
|
||||
*/
|
||||
public final int getUint24() {
|
||||
if (position + 2 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 2));
|
||||
if (position + 2 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 2));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8) | ((0xff & buf[position++]) << 16);
|
||||
@@ -445,8 +476,9 @@ public class LogBuffer {
|
||||
public final int getBeUint24(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 2 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 2)));
|
||||
if (pos + 2 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 2)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position + 2]) | ((0xff & buf[position + 1]) << 8) | ((0xff & buf[position]) << 16);
|
||||
@@ -458,8 +490,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.6.10/include/myisampack.h - mi_usint3korr
|
||||
*/
|
||||
public final int getBeUint24() {
|
||||
if (position + 2 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 2));
|
||||
if (position + 2 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 2));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((0xff & buf[position++]) << 16) | ((0xff & buf[position++]) << 8) | (0xff & buf[position++]);
|
||||
@@ -473,8 +506,9 @@ public class LogBuffer {
|
||||
public final int getInt32(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 3 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 3)));
|
||||
if (pos + 3 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 3)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8) | ((0xff & buf[position + 2]) << 16)
|
||||
@@ -489,8 +523,9 @@ public class LogBuffer {
|
||||
public final int getBeInt32(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 3 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 3)));
|
||||
if (pos + 3 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 3)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position + 3]) | ((0xff & buf[position + 2]) << 8) | ((0xff & buf[position + 1]) << 16)
|
||||
@@ -503,8 +538,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - sint4korr
|
||||
*/
|
||||
public final int getInt32() {
|
||||
if (position + 3 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 3));
|
||||
if (position + 3 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 3));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8) | ((0xff & buf[position++]) << 16)
|
||||
@@ -517,8 +553,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.6.10/include/myisampack.h - mi_sint4korr
|
||||
*/
|
||||
public final int getBeInt32() {
|
||||
if (position + 3 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 3));
|
||||
if (position + 3 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 3));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((buf[position++]) << 24) | ((0xff & buf[position++]) << 16) | ((0xff & buf[position++]) << 8)
|
||||
@@ -533,8 +570,9 @@ public class LogBuffer {
|
||||
public final long getUint32(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 3 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 3)));
|
||||
if (pos + 3 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 3)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
|
||||
@@ -549,8 +587,9 @@ public class LogBuffer {
|
||||
public final long getBeUint32(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 3 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 3)));
|
||||
if (pos + 3 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 3)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position + 3])) | ((long) (0xff & buf[position + 2]) << 8)
|
||||
@@ -563,8 +602,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - uint4korr
|
||||
*/
|
||||
public final long getUint32() {
|
||||
if (position + 3 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 3));
|
||||
if (position + 3 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 3));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
|
||||
@@ -577,8 +617,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.6.10/include/myisampack.h - mi_uint4korr
|
||||
*/
|
||||
public final long getBeUint32() {
|
||||
if (position + 3 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 3));
|
||||
if (position + 3 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 3));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++]) << 24) | ((long) (0xff & buf[position++]) << 16)
|
||||
@@ -591,8 +632,9 @@ public class LogBuffer {
|
||||
public final long getUlong40(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 4 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 4)));
|
||||
if (pos + 4 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 4)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
|
||||
@@ -604,8 +646,9 @@ public class LogBuffer {
|
||||
* Return next 40-bit unsigned int from buffer. (little-endian)
|
||||
*/
|
||||
public final long getUlong40() {
|
||||
if (position + 4 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 4));
|
||||
if (position + 4 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 4));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
|
||||
@@ -621,8 +664,9 @@ public class LogBuffer {
|
||||
public final long getBeUlong40(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 4 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 4)));
|
||||
if (pos + 4 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 4)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position + 4])) | ((long) (0xff & buf[position + 3]) << 8)
|
||||
@@ -636,8 +680,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.6.10/include/myisampack.h - mi_uint5korr
|
||||
*/
|
||||
public final long getBeUlong40() {
|
||||
if (position + 4 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 4));
|
||||
if (position + 4 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 4));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 24)
|
||||
@@ -653,8 +698,9 @@ public class LogBuffer {
|
||||
public final long getLong48(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 5 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 5)));
|
||||
if (pos + 5 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 5)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
|
||||
@@ -670,8 +716,9 @@ public class LogBuffer {
|
||||
public final long getBeLong48(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 5 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 5)));
|
||||
if (pos + 5 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 5)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position + 5])) | ((long) (0xff & buf[position + 4]) << 8)
|
||||
@@ -685,8 +732,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - sint6korr
|
||||
*/
|
||||
public final long getLong48() {
|
||||
if (position + 5 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 5));
|
||||
if (position + 5 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 5));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
|
||||
@@ -700,8 +748,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.6.10/include/myisampack.h - mi_sint6korr
|
||||
*/
|
||||
public final long getBeLong48() {
|
||||
if (position + 5 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 5));
|
||||
if (position + 5 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 5));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (buf[position++]) << 40) | ((long) (0xff & buf[position++]) << 32)
|
||||
@@ -717,8 +766,9 @@ public class LogBuffer {
|
||||
public final long getUlong48(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 5 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 5)));
|
||||
if (pos + 5 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 5)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
|
||||
@@ -734,8 +784,9 @@ public class LogBuffer {
|
||||
public final long getBeUlong48(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 5 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 5)));
|
||||
if (pos + 5 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 5)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position + 5])) | ((long) (0xff & buf[position + 4]) << 8)
|
||||
@@ -749,8 +800,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - uint6korr
|
||||
*/
|
||||
public final long getUlong48() {
|
||||
if (position + 5 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 5));
|
||||
if (position + 5 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 5));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
|
||||
@@ -764,8 +816,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.6.10/include/myisampack.h - mi_uint6korr
|
||||
*/
|
||||
public final long getBeUlong48() {
|
||||
if (position + 5 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 5));
|
||||
if (position + 5 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 5));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++]) << 40) | ((long) (0xff & buf[position++]) << 32)
|
||||
@@ -779,8 +832,9 @@ public class LogBuffer {
|
||||
public final long getUlong56(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 6 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 6)));
|
||||
if (pos + 6 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 6)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
|
||||
@@ -793,8 +847,9 @@ public class LogBuffer {
|
||||
* Return next 56-bit unsigned int from buffer. (little-endian)
|
||||
*/
|
||||
public final long getUlong56() {
|
||||
if (position + 6 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 6));
|
||||
if (position + 6 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 6));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
|
||||
@@ -809,8 +864,9 @@ public class LogBuffer {
|
||||
public final long getBeUlong56(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 6 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 6)));
|
||||
if (pos + 6 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 6)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position + 6])) | ((long) (0xff & buf[position + 5]) << 8)
|
||||
@@ -823,8 +879,9 @@ public class LogBuffer {
|
||||
* Return next 56-bit unsigned int from buffer. (big-endian)
|
||||
*/
|
||||
public final long getBeUlong56() {
|
||||
if (position + 6 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 6));
|
||||
if (position + 6 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 6));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++]) << 48) | ((long) (0xff & buf[position++]) << 40)
|
||||
@@ -841,8 +898,9 @@ public class LogBuffer {
|
||||
public final long getLong64(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 7 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 7)));
|
||||
if (pos + 7 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 7)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
|
||||
@@ -859,8 +917,9 @@ public class LogBuffer {
|
||||
public final long getBeLong64(final int pos) {
|
||||
final int position = origin + pos;
|
||||
|
||||
if (pos + 7 >= limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos < 0 ? pos : (pos + 7)));
|
||||
if (pos + 7 >= limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 7)));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position + 7])) | ((long) (0xff & buf[position + 6]) << 8)
|
||||
@@ -875,8 +934,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.1.60/include/my_global.h - sint8korr
|
||||
*/
|
||||
public final long getLong64() {
|
||||
if (position + 7 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 7));
|
||||
if (position + 7 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 7));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
|
||||
@@ -891,8 +951,9 @@ public class LogBuffer {
|
||||
* @see mysql-5.6.10/include/myisampack.h - mi_sint8korr
|
||||
*/
|
||||
public final long getBeLong64() {
|
||||
if (position + 7 >= origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position - origin + 7));
|
||||
if (position + 7 >= origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position - origin + 7));
|
||||
}
|
||||
|
||||
byte[] buf = buffer;
|
||||
return ((long) (buf[position++]) << 56) | ((long) (0xff & buf[position++]) << 48)
|
||||
@@ -1306,15 +1367,6 @@ public class LogBuffer {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position + binSize - origin));
|
||||
}
|
||||
|
||||
if (precision <= 20 && intg <= 18 && frac <= 9) {
|
||||
// use compact BigDecimal
|
||||
BigDecimal compactDecimal = getBigDecimalCompact(precision, scale, intg, frac, intg0x);
|
||||
if (compactDecimal != null) {
|
||||
position += binSize;
|
||||
return compactDecimal;
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal decimal = getDecimal0(position, intg, frac, // NL
|
||||
intg0,
|
||||
frac0,
|
||||
@@ -1324,162 +1376,6 @@ public class LogBuffer {
|
||||
return decimal;
|
||||
}
|
||||
|
||||
/**
|
||||
* use compact BigDecimal
|
||||
*/
|
||||
private BigDecimal getBigDecimalCompact(int precision, int scale, int intg, int frac, int intg0x) {
|
||||
if (precision > 20 || intg > 18 && frac > 9) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BigDecimal compactDecimal = null;
|
||||
long longValue = 0;
|
||||
int small = 0;
|
||||
int pos = position;
|
||||
byte b0 = buffer[position];
|
||||
final int mask = ((b0 & 0x80) == 0x80) ? 0 : -1;
|
||||
b0 ^= 0x80;
|
||||
|
||||
switch (intg0x) {
|
||||
case 0:
|
||||
if (intg == 0) {
|
||||
longValue = 0;
|
||||
} else {
|
||||
longValue = (b0 << 24)
|
||||
| ((0xff & buffer[pos + 1]) << 16)
|
||||
| ((0xff & buffer[pos + 2]) << 8)
|
||||
| (0xff & buffer[pos + 3]);
|
||||
longValue ^= mask;
|
||||
pos += 4;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
longValue = b0;
|
||||
longValue ^= mask;
|
||||
pos += 1;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
longValue = (b0 << 8) | (0xff & buffer[pos + 1]);
|
||||
longValue ^= mask;
|
||||
pos += 2;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
longValue = (b0 << 16) | ((0xff & buffer[pos + 1]) << 8) | (0xff & buffer[pos + 2]);
|
||||
longValue ^= mask;
|
||||
pos += 3;
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
longValue = (b0 << 24)
|
||||
| ((0xff & buffer[pos + 1]) << 16)
|
||||
| ((0xff & buffer[pos + 2]) << 8)
|
||||
| (0xff & buffer[pos + 3]);
|
||||
longValue ^= mask;
|
||||
pos += 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (intg > 9) {
|
||||
int value = getInt32BE(buffer, pos);
|
||||
value ^= mask;
|
||||
longValue *= 1_000_000_000;
|
||||
longValue += value;
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
int power = 1;
|
||||
if (pos != position) {
|
||||
b0 = buffer[pos];
|
||||
}
|
||||
switch (frac) {
|
||||
case 0:
|
||||
small = 0;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
power = frac == 1 ? 10 : 100;
|
||||
small = b0;
|
||||
small ^= mask;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
power = frac == 3 ? 1_000 : 10_000;
|
||||
small = (b0 << 8) | (0xff & buffer[pos + 1]);
|
||||
small ^= mask;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
power = frac == 5 ? 100_000 : 1_000_000;
|
||||
small = (b0 << 16) | ((0xff & buffer[pos + 1]) << 8) | (0xff & buffer[pos + 2]);
|
||||
small ^= mask;
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
power = frac == 7 ? 10_000_000 : frac == 8 ? 100_000_000 : 1_000_000_000;
|
||||
small = (b0 << 24)
|
||||
| ((0xff & buffer[pos + 1]) << 16)
|
||||
| ((0xff & buffer[pos + 2]) << 8)
|
||||
| (0xff & buffer[pos + 3]);
|
||||
small ^= mask;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (small == 0) {
|
||||
if (frac == 0) {
|
||||
if (mask != 0) {
|
||||
longValue = -longValue;
|
||||
}
|
||||
compactDecimal = BigDecimal.valueOf(longValue, 0);
|
||||
} else if (longValue == 0) {
|
||||
if (scale < 9) {
|
||||
compactDecimal = DECIMAL_ZERO_1_SCALE;
|
||||
} else {
|
||||
compactDecimal = BigDecimal.valueOf(longValue, scale);
|
||||
}
|
||||
} else {
|
||||
if (scale < 9) {
|
||||
long unscaleValue = longValue * 10;
|
||||
if (unscaleValue >= longValue) {
|
||||
if (mask != 0) {
|
||||
unscaleValue = -unscaleValue;
|
||||
}
|
||||
if (unscaleValue == 10) {
|
||||
compactDecimal = DECIMAL_ONE_1_SCALE;
|
||||
} else {
|
||||
compactDecimal = BigDecimal.valueOf(unscaleValue, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
long unscaleValue = longValue * power;
|
||||
if (unscaleValue >= longValue) {
|
||||
if (mask != 0) {
|
||||
unscaleValue = -unscaleValue;
|
||||
}
|
||||
compactDecimal = BigDecimal.valueOf(unscaleValue, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
long unscaleValue = longValue * power + small;
|
||||
if (unscaleValue >= longValue) {
|
||||
if (mask != 0) {
|
||||
unscaleValue = -unscaleValue;
|
||||
}
|
||||
compactDecimal = BigDecimal.valueOf(unscaleValue, scale);
|
||||
}
|
||||
}
|
||||
|
||||
return compactDecimal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return big decimal from buffer.
|
||||
*
|
||||
@@ -1664,8 +1560,9 @@ public class LogBuffer {
|
||||
* @param len The length of MY_BITMAP in bits.
|
||||
*/
|
||||
public final void fillBitmap(BitSet bitmap, final int pos, final int len) {
|
||||
if (pos + ((len + 7) / 8) > limit || pos < 0) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (pos + (len + 7) / 8));
|
||||
if (pos + ((len + 7) / 8) > limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos + (len + 7) / 8));
|
||||
}
|
||||
|
||||
fillBitmap0(bitmap, origin + pos, len);
|
||||
}
|
||||
@@ -1676,9 +1573,9 @@ public class LogBuffer {
|
||||
* @param len The length of MY_BITMAP in bits.
|
||||
*/
|
||||
public final void fillBitmap(BitSet bitmap, final int len) {
|
||||
if (position + ((len + 7) / 8) > origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position
|
||||
+ ((len + 7) / 8) - origin));
|
||||
if (position + ((len + 7) / 8) > origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position + ((len + 7) / 8) - origin));
|
||||
}
|
||||
|
||||
position = fillBitmap0(bitmap, position, len);
|
||||
}
|
||||
@@ -1754,7 +1651,9 @@ public class LogBuffer {
|
||||
* Fill n bytes in this buffer.
|
||||
*/
|
||||
public final void fillBytes(final int pos, byte[] dest, final int destPos, final int len) {
|
||||
if (pos + len > limit || pos < 0) throw new IllegalArgumentException("limit excceed: " + (pos + len));
|
||||
if (pos + len > limit || pos < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (pos + len));
|
||||
}
|
||||
|
||||
System.arraycopy(buffer, origin + pos, dest, destPos, len);
|
||||
}
|
||||
@@ -1763,8 +1662,9 @@ public class LogBuffer {
|
||||
* Fill next n bytes in this buffer.
|
||||
*/
|
||||
public final void fillBytes(byte[] dest, final int destPos, final int len) {
|
||||
if (position + len > origin + limit) throw new IllegalArgumentException("limit excceed: "
|
||||
+ (position + len - origin));
|
||||
if (position + len > origin + limit) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
|
||||
}
|
||||
|
||||
System.arraycopy(buffer, position, dest, destPos, len);
|
||||
position += len;
|
||||
@@ -1795,6 +1695,76 @@ public class LogBuffer {
|
||||
return getData(0, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* mariadb compress log event Get the length of uncompress content.
|
||||
*
|
||||
* @return 0 means error.
|
||||
*/
|
||||
public final long getUncompressLong(int lenPad) {
|
||||
long len = 0;
|
||||
switch (lenPad) {
|
||||
case 1:
|
||||
len = getInt8();
|
||||
break;
|
||||
case 2:
|
||||
len = getBeUint16();
|
||||
break;
|
||||
case 3:
|
||||
len = getBeUint24();
|
||||
break;
|
||||
case 4:
|
||||
len = getBeUint32();
|
||||
break;
|
||||
default:
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* uncompress mariadb log event
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public LogBuffer uncompressBuf() {
|
||||
int lenPad = getInt8();
|
||||
long len = getUncompressLong(lenPad & 0x07);
|
||||
int alg = (lenPad & 0x70) >> 4;
|
||||
LogBuffer buffer = null;
|
||||
try {
|
||||
switch (alg) {
|
||||
case 0:
|
||||
buffer = uncompressZlib(limit - position);
|
||||
break;
|
||||
default:
|
||||
// bad algorithm
|
||||
return this;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("uncompress failed ", e);
|
||||
}
|
||||
|
||||
if (buffer.limit() != len) {
|
||||
throw new IllegalArgumentException(
|
||||
"uncompress lenght not match, expected : " + len + " , but actual : " + buffer.limit());
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private LogBuffer uncompressZlib(int len) throws Exception {
|
||||
if (position + len > limit || position < 0) {
|
||||
throw new IllegalArgumentException("limit excceed: " + (position + len));
|
||||
}
|
||||
|
||||
try (DeflateCompressorInputStream in = new DeflateCompressorInputStream(
|
||||
new ByteArrayInputStream(buffer, position, position + len))) {
|
||||
byte[] decodeBytes = IOUtils.toByteArray(in);
|
||||
return new LogBuffer(decodeBytes, 0, decodeBytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return full hexdump from position.
|
||||
*/
|
||||
@@ -1840,4 +1810,5 @@ public class LogBuffer {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ public final class LogContext {
|
||||
|
||||
private LogEvent gtidLogEvent; // save current gtid log event
|
||||
|
||||
private boolean iterateDecode = false;
|
||||
|
||||
public LogContext(){
|
||||
this.formatDescription = FormatDescriptionLogEvent.FORMAT_DESCRIPTION_EVENT_5_x;
|
||||
}
|
||||
@@ -82,4 +84,12 @@ public final class LogContext {
|
||||
public void setGtidLogEvent(LogEvent gtidLogEvent) {
|
||||
this.gtidLogEvent = gtidLogEvent;
|
||||
}
|
||||
|
||||
public boolean isIterateDecode() {
|
||||
return iterateDecode;
|
||||
}
|
||||
|
||||
public void setIterateDecode(boolean iterateDecode) {
|
||||
this.iterateDecode = iterateDecode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
package com.taobao.tddl.dbsync.binlog;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.taobao.tddl.dbsync.binlog.event.*;
|
||||
import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream;
|
||||
import org.apache.commons.compress.utils.Lists;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;
|
||||
import com.taobao.tddl.dbsync.binlog.event.mariadb.AnnotateRowsEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.mariadb.BinlogCheckPointLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.mariadb.MariaGtidListLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.mariadb.MariaGtidLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.mariadb.StartEncryptionLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.*;
|
||||
import com.taobao.tddl.dbsync.binlog.event.mariadb.*;
|
||||
|
||||
/**
|
||||
* Implements a binary-log decoder.
|
||||
@@ -56,6 +57,8 @@ public final class LogDecoder {
|
||||
handleSet.set(flagIndex);
|
||||
}
|
||||
|
||||
private LogBuffer compressIterateBuffer;
|
||||
|
||||
/**
|
||||
* Decoding an event from binary-log buffer.
|
||||
*
|
||||
@@ -64,7 +67,6 @@ public final class LogDecoder {
|
||||
*/
|
||||
public LogEvent decode(LogBuffer buffer, LogContext context) throws IOException {
|
||||
final int limit = buffer.limit();
|
||||
|
||||
if (limit >= FormatDescriptionLogEvent.LOG_EVENT_HEADER_LEN) {
|
||||
LogHeader header = new LogHeader(buffer, context.getFormatDescription());
|
||||
|
||||
@@ -109,6 +111,59 @@ public final class LogDecoder {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* * process compress binlog payload
|
||||
*
|
||||
* @param event
|
||||
* @param context
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public List<LogEvent> processIterateDecode(LogEvent event, LogContext context) throws IOException {
|
||||
List<LogEvent> events = Lists.newArrayList();
|
||||
if (event.getHeader().getType() == LogEvent.TRANSACTION_PAYLOAD_EVENT) {
|
||||
// iterate for compresss payload
|
||||
TransactionPayloadLogEvent compressEvent = ((TransactionPayloadLogEvent) event);
|
||||
LogBuffer iterateBuffer = null;
|
||||
if (compressEvent.isCompressByZstd()) {
|
||||
try (ZstdCompressorInputStream in = new ZstdCompressorInputStream(
|
||||
new ByteArrayInputStream(compressEvent.getPayload()))) {
|
||||
byte[] decodeBytes = IOUtils.toByteArray(in);
|
||||
iterateBuffer = new LogBuffer(decodeBytes, 0, decodeBytes.length);
|
||||
}
|
||||
} else if (compressEvent.isCompressByNone()) {
|
||||
iterateBuffer = new LogBuffer(compressEvent.getPayload(), 0, compressEvent.getPayload().length);
|
||||
} else {
|
||||
throw new IllegalArgumentException("unknow compress type for " + event.getHeader().getLogFileName()
|
||||
+ ":" + event.getHeader().getLogPos());
|
||||
}
|
||||
|
||||
try {
|
||||
context.setIterateDecode(true);
|
||||
while (iterateBuffer.hasRemaining()) {// iterate
|
||||
LogEvent deEvent = decode(iterateBuffer, context);
|
||||
if (deEvent == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
// compress event logPos = 0
|
||||
deEvent.getHeader().setLogFileName(event.getHeader().getLogFileName());
|
||||
deEvent.getHeader().setLogPos(event.getHeader().getLogPos());
|
||||
// 需要重置payload每个event的eventLen , ack位点更新依赖logPos - eventLen,
|
||||
// 原因:每个payload都是uncompress的eventLen,无法对应物理binlog的eventLen
|
||||
// 隐患:memory计算空间大小时会出现放大的情况,影响getBatch的数量
|
||||
deEvent.getHeader().setEventLen(event.getHeader().getEventLen());
|
||||
events.add(deEvent);
|
||||
}
|
||||
} finally {
|
||||
context.setIterateDecode(false);
|
||||
}
|
||||
} else {
|
||||
// TODO support mariadb compress binlog
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize an event from buffer.
|
||||
*
|
||||
@@ -127,8 +182,12 @@ public final class LogDecoder {
|
||||
}
|
||||
|
||||
if (checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_OFF && checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_UNDEF) {
|
||||
// remove checksum bytes
|
||||
buffer.limit(header.getEventLen() - LogEvent.BINLOG_CHECKSUM_LEN);
|
||||
if (context.isIterateDecode()) {
|
||||
// transaction compress payload在主事件已经处理了checksum,遍历解析event忽略checksum处理
|
||||
} else {
|
||||
// remove checksum bytes
|
||||
buffer.limit(header.getEventLen() - LogEvent.BINLOG_CHECKSUM_LEN);
|
||||
}
|
||||
}
|
||||
GTIDSet gtidSet = context.getGtidSet();
|
||||
LogEvent gtidLogEvent = context.getGtidLogEvent();
|
||||
@@ -360,16 +419,10 @@ public final class LogDecoder {
|
||||
return event;
|
||||
}
|
||||
case LogEvent.TRANSACTION_PAYLOAD_EVENT: {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Skipping unsupported MySQL TRANSACTION_PAYLOAD_EVENT from: " + context.getLogPosition());
|
||||
}
|
||||
break;
|
||||
|
||||
// TransactionPayloadLogEvent event = new TransactionPayloadLogEvent(header,
|
||||
// buffer, descriptionEvent);
|
||||
// /* updating position in context */
|
||||
// logPosition.position = header.getLogPos();
|
||||
// return event;
|
||||
TransactionPayloadLogEvent event = new TransactionPayloadLogEvent(header, buffer, descriptionEvent);
|
||||
/* updating position in context */
|
||||
logPosition.position = header.getLogPos();
|
||||
return event;
|
||||
}
|
||||
case LogEvent.VIEW_CHANGE_EVENT: {
|
||||
ViewChangeEvent event = new ViewChangeEvent(header, buffer, descriptionEvent);
|
||||
@@ -394,6 +447,7 @@ public final class LogDecoder {
|
||||
BinlogCheckPointLogEvent event = new BinlogCheckPointLogEvent(header, buffer, descriptionEvent);
|
||||
/* updating position in context */
|
||||
logPosition.position = header.getLogPos();
|
||||
logPosition.fileName = event.getFilename();
|
||||
return event;
|
||||
}
|
||||
case LogEvent.GTID_EVENT: {
|
||||
@@ -435,31 +489,37 @@ public final class LogDecoder {
|
||||
return event;
|
||||
}
|
||||
case LogEvent.QUERY_COMPRESSED_EVENT: {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Skipping unsupported MaraiDB QUERY_COMPRESSED_EVENT from: " + context.getLogPosition());
|
||||
}
|
||||
break;
|
||||
QueryCompressedLogEvent event = new QueryCompressedLogEvent(header, buffer, descriptionEvent);
|
||||
/* updating position in context */
|
||||
logPosition.position = header.getLogPos();
|
||||
return event;
|
||||
}
|
||||
case LogEvent.WRITE_ROWS_COMPRESSED_EVENT_V1:
|
||||
case LogEvent.WRITE_ROWS_COMPRESSED_EVENT: {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Skipping unsupported MaraiDB WRITE_ROWS_COMPRESSED_EVENT from: " + context.getLogPosition());
|
||||
}
|
||||
break;
|
||||
WriteRowsCompressLogEvent event = new WriteRowsCompressLogEvent(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_COMPRESSED_EVENT_V1:
|
||||
case LogEvent.UPDATE_ROWS_COMPRESSED_EVENT: {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Skipping unsupported MaraiDB UPDATE_ROWS_COMPRESSED_EVENT from: " + context.getLogPosition());
|
||||
}
|
||||
break;
|
||||
UpdateRowsCompressLogEvent event = new UpdateRowsCompressLogEvent(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_COMPRESSED_EVENT_V1:
|
||||
case LogEvent.DELETE_ROWS_COMPRESSED_EVENT: {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Skipping unsupported MaraiDB DELETE_ROWS_COMPRESSED_EVENT from: " + context.getLogPosition());
|
||||
}
|
||||
break;
|
||||
DeleteRowsCompressLogEvent event = new DeleteRowsCompressLogEvent(header, buffer, descriptionEvent);
|
||||
/* updating position in context */
|
||||
logPosition.position = header.getLogPos();
|
||||
event.fillTable(context);
|
||||
header.putGtid(context.getGtidSet(), gtidLogEvent);
|
||||
return event;
|
||||
}
|
||||
default:
|
||||
/*
|
||||
|
||||
@@ -9,9 +9,14 @@ import com.taobao.tddl.dbsync.binlog.LogBuffer;
|
||||
* @author <a href="mailto:changyuan.lh@taobao.com">Changyuan.lh</a>
|
||||
* @version 1.0
|
||||
*/
|
||||
public final class DeleteRowsLogEvent extends RowsLogEvent {
|
||||
public class DeleteRowsLogEvent extends RowsLogEvent {
|
||||
|
||||
public DeleteRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){
|
||||
super(header, buffer, descriptionEvent);
|
||||
super(header, buffer, descriptionEvent, false, false);
|
||||
}
|
||||
|
||||
public DeleteRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,
|
||||
boolean compress){
|
||||
super(header, buffer, descriptionEvent, false, compress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ public final class FormatDescriptionLogEvent extends StartLogEventV3 {
|
||||
public static final int TRANSACTION_CONTEXT_HEADER_LEN = 18;
|
||||
public static final int VIEW_CHANGE_HEADER_LEN = 52;
|
||||
public static final int XA_PREPARE_HEADER_LEN = 0;
|
||||
public static final int TRANSACTION_PAYLOAD_HEADER_LEN = 0;
|
||||
|
||||
public static final int ANNOTATE_ROWS_HEADER_LEN = 0;
|
||||
public static final int BINLOG_CHECKPOINT_HEADER_LEN = 4;
|
||||
@@ -113,14 +114,14 @@ public final class FormatDescriptionLogEvent extends StartLogEventV3 {
|
||||
long calc = getVersionProduct();
|
||||
if (calc >= checksumVersionProduct) {
|
||||
/*
|
||||
* the last bytes are the checksum alg desc and value (or value's
|
||||
* room)
|
||||
* the last bytes are the checksum alg desc and value (or value's room)
|
||||
*/
|
||||
numberOfEventTypes -= BINLOG_CHECKSUM_ALG_DESC_LEN;
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled()) logger.info("common_header_len= " + commonHeaderLen + ", number_of_event_types= "
|
||||
+ numberOfEventTypes);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("common_header_len= " + commonHeaderLen + ", number_of_event_types= " + numberOfEventTypes);
|
||||
}
|
||||
}
|
||||
|
||||
/** MySQL 5.0 format descriptions. */
|
||||
@@ -212,6 +213,7 @@ public final class FormatDescriptionLogEvent extends StartLogEventV3 {
|
||||
postHeaderLen[VIEW_CHANGE_EVENT - 1] = VIEW_CHANGE_HEADER_LEN;
|
||||
postHeaderLen[XA_PREPARE_LOG_EVENT - 1] = XA_PREPARE_HEADER_LEN;
|
||||
postHeaderLen[PARTIAL_UPDATE_ROWS_EVENT - 1] = ROWS_HEADER_LEN_V2;
|
||||
postHeaderLen[TRANSACTION_PAYLOAD_EVENT - 1] = TRANSACTION_PAYLOAD_HEADER_LEN;
|
||||
|
||||
// mariadb 10
|
||||
postHeaderLen[ANNOTATE_ROWS_EVENT - 1] = ANNOTATE_ROWS_HEADER_LEN;
|
||||
@@ -219,6 +221,15 @@ public final class FormatDescriptionLogEvent extends StartLogEventV3 {
|
||||
postHeaderLen[GTID_EVENT - 1] = GTID_HEADER_LEN;
|
||||
postHeaderLen[GTID_LIST_EVENT - 1] = GTID_LIST_HEADER_LEN;
|
||||
postHeaderLen[START_ENCRYPTION_EVENT - 1] = START_ENCRYPTION_HEADER_LEN;
|
||||
|
||||
// mariadb compress
|
||||
postHeaderLen[QUERY_COMPRESSED_EVENT - 1] = QUERY_COMPRESSED_EVENT;
|
||||
postHeaderLen[WRITE_ROWS_COMPRESSED_EVENT - 1] = ROWS_HEADER_LEN_V2;
|
||||
postHeaderLen[UPDATE_ROWS_COMPRESSED_EVENT - 1] = ROWS_HEADER_LEN_V2;
|
||||
postHeaderLen[DELETE_ROWS_COMPRESSED_EVENT - 1] = ROWS_HEADER_LEN_V2;
|
||||
postHeaderLen[WRITE_ROWS_COMPRESSED_EVENT_V1 - 1] = ROWS_HEADER_LEN_V1;
|
||||
postHeaderLen[UPDATE_ROWS_COMPRESSED_EVENT_V1 - 1] = ROWS_HEADER_LEN_V1;
|
||||
postHeaderLen[DELETE_ROWS_COMPRESSED_EVENT_V1 - 1] = ROWS_HEADER_LEN_V1;
|
||||
break;
|
||||
|
||||
case 3: /* 4.0.x x>=2 */
|
||||
|
||||
@@ -23,8 +23,8 @@ public class GtidLogEvent extends LogEvent {
|
||||
private boolean commitFlag;
|
||||
private UUID sid;
|
||||
private long gno;
|
||||
private Long lastCommitted;
|
||||
private Long sequenceNumber;
|
||||
private long lastCommitted;
|
||||
private long sequenceNumber;
|
||||
|
||||
public GtidLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){
|
||||
super(header);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.taobao.tddl.dbsync.binlog.event;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;
|
||||
import com.taobao.tddl.dbsync.binlog.LogBuffer;
|
||||
import com.taobao.tddl.dbsync.binlog.LogEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Common-Header, documented in the table @ref Table_common_header "below",
|
||||
* always has the same form and length within one version of MySQL. Each event
|
||||
@@ -66,7 +66,7 @@ import java.util.Map;
|
||||
*/
|
||||
public final class LogHeader {
|
||||
|
||||
protected final int type;
|
||||
protected int type;
|
||||
|
||||
/**
|
||||
* The offset in the log where this event originally appeared (it is
|
||||
@@ -293,6 +293,12 @@ public final class LogHeader {
|
||||
public void setLogFileName(String logFileName) {
|
||||
this.logFileName = logFileName;
|
||||
}
|
||||
public void setLogPos(long logPos) {
|
||||
this.logPos = logPos;
|
||||
}
|
||||
public void setEventLen(int eventLen) {
|
||||
this.eventLen = eventLen;
|
||||
}
|
||||
|
||||
private void processCheckSum(LogBuffer buffer) {
|
||||
if (checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_OFF && checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_UNDEF) {
|
||||
@@ -320,7 +326,7 @@ public final class LogHeader {
|
||||
if (gtidSet != null) {
|
||||
gtidMap.put(GTID_SET_STRING, gtidSet.toString());
|
||||
if (gtidEvent != null && gtidEvent instanceof GtidLogEvent) {
|
||||
GtidLogEvent event = (GtidLogEvent)gtidEvent;
|
||||
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()));
|
||||
|
||||
@@ -438,9 +438,13 @@ public class QueryLogEvent extends LogEvent {
|
||||
private String timezone;
|
||||
|
||||
public QueryLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent)
|
||||
throws IOException{
|
||||
super(header);
|
||||
throws IOException{
|
||||
this(header, buffer, descriptionEvent, false);
|
||||
}
|
||||
|
||||
public QueryLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,
|
||||
boolean compress) throws IOException{
|
||||
super(header);
|
||||
final int commonHeaderLen = descriptionEvent.commonHeaderLen;
|
||||
final int postHeaderLen = descriptionEvent.postHeaderLen[header.type - 1];
|
||||
/*
|
||||
@@ -495,10 +499,15 @@ public class QueryLogEvent extends LogEvent {
|
||||
unpackVariables(buffer, end);
|
||||
buffer.position(end);
|
||||
buffer.limit(limit);
|
||||
|
||||
/* A 2nd variable part; this is common to all versions */
|
||||
final int queryLen = dataLen - dbLen - 1;
|
||||
dbname = buffer.getFixName(dbLen + 1);
|
||||
int queryLen = dataLen - dbLen - 1;
|
||||
if (compress) {
|
||||
// mariadb compress log event
|
||||
// see https://github.com/alibaba/canal/issues/4388
|
||||
buffer = buffer.uncompressBuf();
|
||||
queryLen = buffer.limit();
|
||||
}
|
||||
if (clientCharset >= 0) {
|
||||
charset = CharsetConversion.getNioCharset(clientCharset);
|
||||
|
||||
|
||||
@@ -88,9 +88,10 @@ public final class RotateLogEvent extends LogEvent {
|
||||
|
||||
final int filenameOffset = headerSize + postHeaderLen;
|
||||
int filenameLen = buffer.limit() - filenameOffset;
|
||||
if (filenameLen > FN_REFLEN - 1) filenameLen = FN_REFLEN - 1;
|
||||
if (filenameLen > FN_REFLEN - 1) {
|
||||
filenameLen = FN_REFLEN - 1;
|
||||
}
|
||||
buffer.position(filenameOffset);
|
||||
|
||||
filename = buffer.getFixString(filenameLen);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ package com.taobao.tddl.dbsync.binlog.event;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.BitSet;
|
||||
|
||||
import com.taobao.tddl.dbsync.binlog.exception.TableIdNotFoundException;
|
||||
import com.taobao.tddl.dbsync.binlog.LogBuffer;
|
||||
import com.taobao.tddl.dbsync.binlog.LogContext;
|
||||
import com.taobao.tddl.dbsync.binlog.LogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent.ColumnInfo;
|
||||
import com.taobao.tddl.dbsync.binlog.exception.TableIdNotFoundException;
|
||||
|
||||
/**
|
||||
* Common base class for all row-containing log events.
|
||||
@@ -118,9 +118,14 @@ public abstract class RowsLogEvent extends LogEvent {
|
||||
this(header, buffer, descriptionEvent, false);
|
||||
}
|
||||
|
||||
public RowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent, boolean partial){
|
||||
super(header);
|
||||
public RowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,
|
||||
boolean partial){
|
||||
this(header, buffer, descriptionEvent, false, false);
|
||||
}
|
||||
|
||||
public RowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent, boolean partial,
|
||||
boolean compress){
|
||||
super(header);
|
||||
final int commonHeaderLen = descriptionEvent.commonHeaderLen;
|
||||
final int postHeaderLen = descriptionEvent.postHeaderLen[header.type - 1];
|
||||
int headerLen = 0;
|
||||
@@ -167,7 +172,8 @@ public abstract class RowsLogEvent extends LogEvent {
|
||||
columns = buffer.getBitmap(columnLen);
|
||||
|
||||
if (header.type == UPDATE_ROWS_EVENT_V1 || header.type == UPDATE_ROWS_EVENT
|
||||
|| header.type == PARTIAL_UPDATE_ROWS_EVENT) {
|
||||
|| header.type == PARTIAL_UPDATE_ROWS_EVENT || header.type == UPDATE_ROWS_COMPRESSED_EVENT
|
||||
|| header.type == UPDATE_ROWS_COMPRESSED_EVENT_V1) {
|
||||
changeColumns = buffer.getBitmap(columnLen);
|
||||
} else {
|
||||
changeColumns = columns;
|
||||
@@ -175,6 +181,18 @@ public abstract class RowsLogEvent extends LogEvent {
|
||||
|
||||
// XXX: Don't handle buffer in another thread.
|
||||
int dataSize = buffer.limit() - buffer.position();
|
||||
if (compress) {
|
||||
// mariadb compress log event
|
||||
// see https://github.com/alibaba/canal/issues/4388
|
||||
buffer = buffer.uncompressBuf();
|
||||
dataSize = buffer.limit();
|
||||
// rewrite type
|
||||
if (postHeaderLen == FormatDescriptionLogEvent.ROWS_HEADER_LEN_V2) {
|
||||
header.type = header.type - WRITE_ROWS_COMPRESSED_EVENT + WRITE_ROWS_EVENT;
|
||||
} else {
|
||||
header.type = header.type - WRITE_ROWS_COMPRESSED_EVENT_V1 + WRITE_ROWS_EVENT_V1;
|
||||
}
|
||||
}
|
||||
rowsBuf = buffer.duplicate(dataSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,91 @@ import com.taobao.tddl.dbsync.binlog.LogEvent;
|
||||
|
||||
/**
|
||||
* @author agapple 2022年5月23日 下午7:05:39
|
||||
* @version 1.1.6
|
||||
* @version 1.1.7
|
||||
* @since mysql 8.0.20
|
||||
*/
|
||||
public class TransactionPayloadLogEvent extends LogEvent {
|
||||
|
||||
public static final short COMPRESSION_TYPE_MIN_LENGTH = 1;
|
||||
public static final short COMPRESSION_TYPE_MAX_LENGTH = 9;
|
||||
public static final short PAYLOAD_SIZE_MIN_LENGTH = 0;
|
||||
public static final short PAYLOAD_SIZE_MAX_LENGTH = 9;
|
||||
public static final short UNCOMPRESSED_SIZE_MIN_LENGTH = 0;
|
||||
public static final short UNCOMPRESSED_SIZE_MAX_LENGTH = 9;
|
||||
public static final int MAX_DATA_LENGTH = COMPRESSION_TYPE_MAX_LENGTH
|
||||
+ PAYLOAD_SIZE_MAX_LENGTH
|
||||
+ UNCOMPRESSED_SIZE_MAX_LENGTH;
|
||||
|
||||
/** Marks the end of the payload header. */
|
||||
public static final int OTW_PAYLOAD_HEADER_END_MARK = 0;
|
||||
|
||||
/** The payload field */
|
||||
public static final int OTW_PAYLOAD_SIZE_FIELD = 1;
|
||||
|
||||
/** The compression type field */
|
||||
public static final int OTW_PAYLOAD_COMPRESSION_TYPE_FIELD = 2;
|
||||
|
||||
/** The uncompressed size field */
|
||||
public static final int OTW_PAYLOAD_UNCOMPRESSED_SIZE_FIELD = 3;
|
||||
|
||||
/* ZSTD compression. */
|
||||
public final static int COMPRESS_TYPE_ZSTD = 0;
|
||||
/* No compression. */
|
||||
public final static int COMPRESS_TYPE_NONE = 255;
|
||||
|
||||
private long m_compression_type = COMPRESS_TYPE_NONE;
|
||||
private long m_payload_size;
|
||||
private long m_uncompressed_size;
|
||||
private byte[] m_payload;
|
||||
|
||||
public TransactionPayloadLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){
|
||||
super(header);
|
||||
|
||||
final int commonHeaderLen = descriptionEvent.getCommonHeaderLen();
|
||||
final int postHeaderLen = descriptionEvent.getPostHeaderLen()[header.getType() - 1];
|
||||
|
||||
int offset = commonHeaderLen;
|
||||
buffer.position(offset);
|
||||
long type = 0, length = 0;
|
||||
while (buffer.hasRemaining()) {
|
||||
type = buffer.getPackedLong(); // type
|
||||
if (type == OTW_PAYLOAD_HEADER_END_MARK) {
|
||||
break;
|
||||
}
|
||||
|
||||
length = buffer.getPackedLong(); // length
|
||||
switch ((int) type) {
|
||||
case OTW_PAYLOAD_SIZE_FIELD:
|
||||
m_payload_size = buffer.getPackedLong(); // value
|
||||
break;
|
||||
case OTW_PAYLOAD_COMPRESSION_TYPE_FIELD:
|
||||
m_compression_type = buffer.getPackedLong(); // value
|
||||
break;
|
||||
case OTW_PAYLOAD_UNCOMPRESSED_SIZE_FIELD:
|
||||
m_uncompressed_size = buffer.getPackedLong(); // value
|
||||
break;
|
||||
default:
|
||||
buffer.forward((int) length);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (m_uncompressed_size == 0) {
|
||||
m_uncompressed_size = m_payload_size;
|
||||
}
|
||||
m_payload = buffer.getData((int) m_payload_size);
|
||||
}
|
||||
|
||||
public boolean isCompressByZstd() {
|
||||
return m_compression_type == COMPRESS_TYPE_ZSTD;
|
||||
}
|
||||
|
||||
public boolean isCompressByNone() {
|
||||
return m_compression_type == COMPRESS_TYPE_NONE;
|
||||
}
|
||||
|
||||
public byte[] getPayload() {
|
||||
return m_payload;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,19 @@ import com.taobao.tddl.dbsync.binlog.LogBuffer;
|
||||
* @author <a href="mailto:changyuan.lh@taobao.com">Changyuan.lh</a>
|
||||
* @version 1.0
|
||||
*/
|
||||
public final class UpdateRowsLogEvent extends RowsLogEvent {
|
||||
public class UpdateRowsLogEvent extends RowsLogEvent {
|
||||
|
||||
public UpdateRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){
|
||||
super(header, buffer, descriptionEvent, false);
|
||||
super(header, buffer, descriptionEvent, false , false);
|
||||
}
|
||||
|
||||
public UpdateRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,
|
||||
boolean partial){
|
||||
super(header, buffer, descriptionEvent, partial);
|
||||
super(header, buffer, descriptionEvent, partial ,false);
|
||||
}
|
||||
|
||||
public UpdateRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,
|
||||
boolean partial , boolean compress){
|
||||
super(header, buffer, descriptionEvent, partial , compress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,14 @@ import com.taobao.tddl.dbsync.binlog.LogBuffer;
|
||||
* @author <a href="mailto:changyuan.lh@taobao.com">Changyuan.lh</a>
|
||||
* @version 1.0
|
||||
*/
|
||||
public final class WriteRowsLogEvent extends RowsLogEvent {
|
||||
public class WriteRowsLogEvent extends RowsLogEvent {
|
||||
|
||||
public WriteRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){
|
||||
super(header, buffer, descriptionEvent);
|
||||
super(header, buffer, descriptionEvent, false, false);
|
||||
}
|
||||
|
||||
public WriteRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,
|
||||
boolean compress){
|
||||
super(header, buffer, descriptionEvent, false, compress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,20 @@ import com.taobao.tddl.dbsync.binlog.event.LogHeader;
|
||||
*/
|
||||
public class BinlogCheckPointLogEvent extends IgnorableLogEvent {
|
||||
|
||||
private final String filename;
|
||||
|
||||
public BinlogCheckPointLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){
|
||||
super(header, buffer, descriptionEvent);
|
||||
// do nothing , just mariadb binlog checkpoint
|
||||
// mariadb binlog checkpoint
|
||||
final int headerSize = descriptionEvent.getCommonHeaderLen();
|
||||
final int postHeaderLen = descriptionEvent.getPostHeaderLen()[getHeader().getType() - 1];
|
||||
|
||||
buffer.position(headerSize);
|
||||
long binlogFileLen = buffer.getUint32();
|
||||
filename = buffer.getFixString((int) binlogFileLen);
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package com.taobao.tddl.dbsync.binlog.event.mariadb;
|
||||
@@ -0,0 +1 @@
|
||||
package com.taobao.tddl.dbsync.binlog.event.mariadb;
|
||||
@@ -0,0 +1 @@
|
||||
package com.taobao.tddl.dbsync.binlog.event.mariadb;
|
||||
@@ -0,0 +1 @@
|
||||
package com.taobao.tddl.dbsync.binlog.event.mariadb;
|
||||
@@ -4,20 +4,15 @@ import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.Statement;
|
||||
import java.util.List;
|
||||
|
||||
import com.taobao.tddl.dbsync.binlog.event.mariadb.BinlogCheckPointLogEvent;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.taobao.tddl.dbsync.binlog.event.DeleteRowsLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.QueryLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.RotateLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.RowsQueryLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.UpdateRowsLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.WriteRowsLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.XidLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.*;
|
||||
import com.taobao.tddl.dbsync.binlog.event.mariadb.AnnotateRowsEvent;
|
||||
@Ignore
|
||||
|
||||
public class DirectLogFetcherTest extends BaseLogFetcherTest {
|
||||
|
||||
@Test
|
||||
@@ -25,52 +20,20 @@ public class DirectLogFetcherTest extends BaseLogFetcherTest {
|
||||
DirectLogFetcher fecther = new DirectLogFetcher();
|
||||
try {
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306", "root", "hello");
|
||||
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306", "root", "123456");
|
||||
Statement statement = connection.createStatement();
|
||||
statement.execute("SET @master_binlog_checksum='@@global.binlog_checksum'");
|
||||
statement.execute("SET @mariadb_slave_capability='" + LogEvent.MARIA_SLAVE_CAPABILITY_MINE + "'");
|
||||
|
||||
fecther.open(connection, "mysql-bin.000007", 89797036L, 2);
|
||||
fecther.open(connection, "mysql-bin.000002", 4L, 1);
|
||||
|
||||
LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);
|
||||
LogContext context = new LogContext();
|
||||
while (fecther.fetch()) {
|
||||
LogEvent event = decoder.decode(fecther, context);
|
||||
int eventType = event.getHeader().getType();
|
||||
switch (eventType) {
|
||||
case LogEvent.ROTATE_EVENT:
|
||||
binlogFileName = ((RotateLogEvent) event).getFilename();
|
||||
break;
|
||||
case LogEvent.WRITE_ROWS_EVENT_V1:
|
||||
case LogEvent.WRITE_ROWS_EVENT:
|
||||
parseRowsEvent((WriteRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.UPDATE_ROWS_EVENT_V1:
|
||||
case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:
|
||||
case LogEvent.UPDATE_ROWS_EVENT:
|
||||
parseRowsEvent((UpdateRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.DELETE_ROWS_EVENT_V1:
|
||||
case LogEvent.DELETE_ROWS_EVENT:
|
||||
parseRowsEvent((DeleteRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.QUERY_EVENT:
|
||||
parseQueryEvent((QueryLogEvent) event);
|
||||
break;
|
||||
case LogEvent.ROWS_QUERY_LOG_EVENT:
|
||||
parseRowsQueryEvent((RowsQueryLogEvent) event);
|
||||
break;
|
||||
case LogEvent.ANNOTATE_ROWS_EVENT:
|
||||
parseAnnotateRowsEvent((AnnotateRowsEvent) event);
|
||||
break;
|
||||
case LogEvent.XID_EVENT:
|
||||
parseXidEvent((XidLogEvent) event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
processEvent(event, decoder, context);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.getMessage());
|
||||
} finally {
|
||||
@@ -82,4 +45,49 @@ public class DirectLogFetcherTest extends BaseLogFetcherTest {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void processEvent(LogEvent event, LogDecoder decoder, LogContext context) throws Throwable {
|
||||
int eventType = event.getHeader().getType();
|
||||
switch (eventType) {
|
||||
case LogEvent.ROTATE_EVENT:
|
||||
binlogFileName = ((RotateLogEvent) event).getFilename();
|
||||
break;
|
||||
case LogEvent.BINLOG_CHECKPOINT_EVENT:
|
||||
binlogFileName = ((BinlogCheckPointLogEvent) event).getFilename();
|
||||
break;
|
||||
case LogEvent.WRITE_ROWS_EVENT_V1:
|
||||
case LogEvent.WRITE_ROWS_EVENT:
|
||||
parseRowsEvent((WriteRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.UPDATE_ROWS_EVENT_V1:
|
||||
case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:
|
||||
case LogEvent.UPDATE_ROWS_EVENT:
|
||||
parseRowsEvent((UpdateRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.DELETE_ROWS_EVENT_V1:
|
||||
case LogEvent.DELETE_ROWS_EVENT:
|
||||
parseRowsEvent((DeleteRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.QUERY_EVENT:
|
||||
parseQueryEvent((QueryLogEvent) event);
|
||||
break;
|
||||
case LogEvent.ROWS_QUERY_LOG_EVENT:
|
||||
parseRowsQueryEvent((RowsQueryLogEvent) event);
|
||||
break;
|
||||
case LogEvent.ANNOTATE_ROWS_EVENT:
|
||||
parseAnnotateRowsEvent((AnnotateRowsEvent) event);
|
||||
break;
|
||||
case LogEvent.XID_EVENT:
|
||||
parseXidEvent((XidLogEvent) event);
|
||||
break;
|
||||
case LogEvent.TRANSACTION_PAYLOAD_EVENT:
|
||||
List<LogEvent> events = decoder.processIterateDecode(event, context);
|
||||
for (LogEvent deEvent : events) {
|
||||
processEvent(deEvent, decoder, context);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.taobao.tddl.dbsync.binlog;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
@@ -43,43 +44,9 @@ public class FileLogFetcherTest extends BaseLogFetcherTest {
|
||||
while (fetcher.fetch()) {
|
||||
LogEvent event = null;
|
||||
event = decoder.decode(fetcher, context);
|
||||
if (event != null) {
|
||||
int eventType = event.getHeader().getType();
|
||||
switch (eventType) {
|
||||
case LogEvent.ROTATE_EVENT:
|
||||
binlogFileName = ((RotateLogEvent) event).getFilename();
|
||||
break;
|
||||
case LogEvent.WRITE_ROWS_EVENT_V1:
|
||||
case LogEvent.WRITE_ROWS_EVENT:
|
||||
parseRowsEvent((WriteRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.UPDATE_ROWS_EVENT_V1:
|
||||
case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:
|
||||
case LogEvent.UPDATE_ROWS_EVENT:
|
||||
parseRowsEvent((UpdateRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.DELETE_ROWS_EVENT_V1:
|
||||
case LogEvent.DELETE_ROWS_EVENT:
|
||||
parseRowsEvent((DeleteRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.QUERY_EVENT:
|
||||
parseQueryEvent((QueryLogEvent) event);
|
||||
break;
|
||||
case LogEvent.ROWS_QUERY_LOG_EVENT:
|
||||
parseRowsQueryEvent((RowsQueryLogEvent) event);
|
||||
break;
|
||||
case LogEvent.ANNOTATE_ROWS_EVENT:
|
||||
parseAnnotateRowsEvent((AnnotateRowsEvent) event);
|
||||
break;
|
||||
case LogEvent.XID_EVENT:
|
||||
parseXidEvent((XidLogEvent) event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
processEvent(event, decoder, context);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
Assert.fail(e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
@@ -89,4 +56,46 @@ public class FileLogFetcherTest extends BaseLogFetcherTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void processEvent(LogEvent event, LogDecoder decoder, LogContext context) throws Throwable {
|
||||
int eventType = event.getHeader().getType();
|
||||
switch (eventType) {
|
||||
case LogEvent.ROTATE_EVENT:
|
||||
binlogFileName = ((RotateLogEvent) event).getFilename();
|
||||
break;
|
||||
case LogEvent.WRITE_ROWS_EVENT_V1:
|
||||
case LogEvent.WRITE_ROWS_EVENT:
|
||||
parseRowsEvent((WriteRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.UPDATE_ROWS_EVENT_V1:
|
||||
case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:
|
||||
case LogEvent.UPDATE_ROWS_EVENT:
|
||||
parseRowsEvent((UpdateRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.DELETE_ROWS_EVENT_V1:
|
||||
case LogEvent.DELETE_ROWS_EVENT:
|
||||
parseRowsEvent((DeleteRowsLogEvent) event);
|
||||
break;
|
||||
case LogEvent.QUERY_EVENT:
|
||||
parseQueryEvent((QueryLogEvent) event);
|
||||
break;
|
||||
case LogEvent.ROWS_QUERY_LOG_EVENT:
|
||||
parseRowsQueryEvent((RowsQueryLogEvent) event);
|
||||
break;
|
||||
case LogEvent.ANNOTATE_ROWS_EVENT:
|
||||
parseAnnotateRowsEvent((AnnotateRowsEvent) event);
|
||||
break;
|
||||
case LogEvent.XID_EVENT:
|
||||
parseXidEvent((XidLogEvent) event);
|
||||
break;
|
||||
case LogEvent.TRANSACTION_PAYLOAD_EVENT:
|
||||
List<LogEvent> events = decoder.processIterateDecode(event, context);
|
||||
for (LogEvent deEvent : events) {
|
||||
processEvent(deEvent, decoder, context);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
<artifactId>canal</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.7</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>com.alibaba.otter</groupId>
|
||||
|
||||
@@ -81,7 +81,7 @@ esac
|
||||
|
||||
JavaVersion=`$JAVA -version 2>&1 |awk 'NR==1{ gsub(/"/,""); print $3 }' | awk -F '.' '{print $1}'`
|
||||
str=`file -L $JAVA | grep 64-bit`
|
||||
JAVA_OPTS="$JAVA_OPTS -Xss256k -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs"
|
||||
JAVA_OPTS="$JAVA_OPTS -Xss1m -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs"
|
||||
|
||||
if [ $JavaVersion -ge 11 ] ; then
|
||||
#JAVA_OPTS="$JAVA_OPTS -Xlog:gc*:$base_log/gc.log:time "
|
||||
|
||||
@@ -30,6 +30,7 @@ public class CanalConstants {
|
||||
public static final String CANAL_WITHOUT_NETTY = ROOT + "." + "withoutNetty";
|
||||
|
||||
public static final String CANAL_DESTINATIONS = ROOT + "." + "destinations";
|
||||
public static final String CANAL_DESTINATIONS_EXPR = ROOT + "." + "destinations.expr";
|
||||
public static final String CANAL_AUTO_SCAN = ROOT + "." + "auto.scan";
|
||||
public static final String CANAL_AUTO_SCAN_INTERVAL = ROOT + "." + "auto.scan.interval";
|
||||
public static final String CANAL_CONF_DIR = ROOT + "." + "conf.dir";
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
package com.alibaba.otter.canal.deployer;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.I0Itec.zkclient.IZkStateListener;
|
||||
import org.I0Itec.zkclient.exception.ZkNoNodeException;
|
||||
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.zookeeper.Watcher.Event.KeeperState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import com.alibaba.otter.canal.common.utils.AddressUtils;
|
||||
import com.alibaba.otter.canal.common.zookeeper.ZkClientx;
|
||||
import com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;
|
||||
@@ -36,6 +23,26 @@ import com.alibaba.otter.canal.server.netty.CanalServerWithNetty;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.MigrateMap;
|
||||
import org.I0Itec.zkclient.IZkStateListener;
|
||||
import org.I0Itec.zkclient.exception.ZkNoNodeException;
|
||||
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.zookeeper.Watcher.Event.KeeperState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.alibaba.otter.canal.deployer.CanalConstants.CANAL_DESTINATIONS;
|
||||
import static com.alibaba.otter.canal.deployer.CanalConstants.CANAL_DESTINATIONS_EXPR;
|
||||
|
||||
/**
|
||||
* canal调度控制器
|
||||
@@ -58,7 +65,7 @@ public class CanalController {
|
||||
private boolean autoScan = true;
|
||||
private InstanceAction defaultAction;
|
||||
private Map<InstanceMode, InstanceConfigMonitor> instanceConfigMonitors;
|
||||
private CanalServerWithEmbedded embededCanalServer;
|
||||
private CanalServerWithEmbedded embeddedCanalServer;
|
||||
private CanalServerWithNetty canalServer;
|
||||
|
||||
private CanalInstanceGenerator instanceGenerator;
|
||||
@@ -102,15 +109,15 @@ public class CanalController {
|
||||
registerIp = getProperty(properties, CanalConstants.CANAL_REGISTER_IP);
|
||||
port = Integer.valueOf(getProperty(properties, CanalConstants.CANAL_PORT, "11111"));
|
||||
adminPort = Integer.valueOf(getProperty(properties, CanalConstants.CANAL_ADMIN_PORT, "11110"));
|
||||
embededCanalServer = CanalServerWithEmbedded.instance();
|
||||
embededCanalServer.setCanalInstanceGenerator(instanceGenerator);// 设置自定义的instanceGenerator
|
||||
embeddedCanalServer = CanalServerWithEmbedded.instance();
|
||||
embeddedCanalServer.setCanalInstanceGenerator(instanceGenerator);// 设置自定义的instanceGenerator
|
||||
int metricsPort = Integer.valueOf(getProperty(properties, CanalConstants.CANAL_METRICS_PULL_PORT, "11112"));
|
||||
embededCanalServer.setMetricsPort(metricsPort);
|
||||
embeddedCanalServer.setMetricsPort(metricsPort);
|
||||
|
||||
this.adminUser = getProperty(properties, CanalConstants.CANAL_ADMIN_USER);
|
||||
this.adminPasswd = getProperty(properties, CanalConstants.CANAL_ADMIN_PASSWD);
|
||||
embededCanalServer.setUser(getProperty(properties, CanalConstants.CANAL_USER));
|
||||
embededCanalServer.setPasswd(getProperty(properties, CanalConstants.CANAL_PASSWD));
|
||||
embeddedCanalServer.setUser(getProperty(properties, CanalConstants.CANAL_USER));
|
||||
embeddedCanalServer.setPasswd(getProperty(properties, CanalConstants.CANAL_PASSWD));
|
||||
|
||||
String canalWithoutNetty = getProperty(properties, CanalConstants.CANAL_WITHOUT_NETTY);
|
||||
if (canalWithoutNetty == null || "false".equals(canalWithoutNetty)) {
|
||||
@@ -149,7 +156,7 @@ public class CanalController {
|
||||
public void processActiveEnter() {
|
||||
try {
|
||||
MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));
|
||||
embededCanalServer.start(destination);
|
||||
embeddedCanalServer.start(destination);
|
||||
if (canalMQStarter != null) {
|
||||
canalMQStarter.startDestination(destination);
|
||||
}
|
||||
@@ -164,7 +171,7 @@ public class CanalController {
|
||||
if (canalMQStarter != null) {
|
||||
canalMQStarter.stopDestination(destination);
|
||||
}
|
||||
embededCanalServer.stop(destination);
|
||||
embeddedCanalServer.stop(destination);
|
||||
} finally {
|
||||
MDC.remove(CanalConstants.MDC_DESTINATION);
|
||||
}
|
||||
@@ -232,7 +239,7 @@ public class CanalController {
|
||||
instanceConfigs.put(destination, config);
|
||||
}
|
||||
|
||||
if (!embededCanalServer.isStart(destination)) {
|
||||
if (!embeddedCanalServer.isStart(destination)) {
|
||||
// HA机制启动
|
||||
ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(destination);
|
||||
if (!config.getLazy() && !runningMonitor.isStart()) {
|
||||
@@ -247,7 +254,7 @@ public class CanalController {
|
||||
// 此处的stop,代表强制退出,非HA机制,所以需要退出HA的monitor和配置信息
|
||||
InstanceConfig config = instanceConfigs.remove(destination);
|
||||
if (config != null) {
|
||||
embededCanalServer.stop(destination);
|
||||
embeddedCanalServer.stop(destination);
|
||||
ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(destination);
|
||||
if (runningMonitor.isStart()) {
|
||||
runningMonitor.stop();
|
||||
@@ -377,7 +384,7 @@ public class CanalController {
|
||||
instanceGenerator.setSpringXml(config.getSpringXml());
|
||||
return instanceGenerator.generate(destination);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("unknow mode :" + config.getMode());
|
||||
throw new UnsupportedOperationException("unknown mode :" + config.getMode());
|
||||
}
|
||||
|
||||
};
|
||||
@@ -390,7 +397,7 @@ public class CanalController {
|
||||
}
|
||||
|
||||
private void initInstanceConfig(Properties properties) {
|
||||
String destinationStr = getProperty(properties, CanalConstants.CANAL_DESTINATIONS);
|
||||
String destinationStr = getDestinations(properties);
|
||||
String[] destinations = StringUtils.split(destinationStr, CanalConstants.CANAL_DESTINATION_SPLIT);
|
||||
|
||||
for (String destination : destinations) {
|
||||
@@ -461,6 +468,40 @@ public class CanalController {
|
||||
return StringUtils.trim(value);
|
||||
}
|
||||
|
||||
public static String getDestinations(Properties properties) {
|
||||
String expr = getProperty(properties, CANAL_DESTINATIONS_EXPR);
|
||||
if (StringUtils.isNotBlank(expr)) {
|
||||
return parseExpr(expr);
|
||||
} else {
|
||||
return getProperty(properties, CANAL_DESTINATIONS);
|
||||
}
|
||||
}
|
||||
|
||||
private static String parseExpr(String expr) {
|
||||
String prefix = StringUtils.substringBefore(expr, "{");
|
||||
String range = StringUtils.substringAfter(expr, "{");
|
||||
range = StringUtils.substringBefore(range, "}");
|
||||
|
||||
String regex = "(\\d+)-(\\d+)";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(range);
|
||||
if (matcher.find()) {
|
||||
String head = matcher.group(1);
|
||||
String tail = matcher.group(2);
|
||||
int start = Integer.parseInt(head);
|
||||
int end = Integer.parseInt(tail);
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
for (int i = start; i <= end; i++) {
|
||||
String d = prefix + i;
|
||||
list.add(d);
|
||||
}
|
||||
return list.stream().map(Object::toString).collect(Collectors.joining(","));
|
||||
} else {
|
||||
throw new CanalServerException("invalid destinations expr " + expr);
|
||||
}
|
||||
}
|
||||
|
||||
public void start() throws Throwable {
|
||||
logger.info("## start the canal server[{}({}):{}]", ip, registerIp, port);
|
||||
// 创建整个canal的工作节点
|
||||
@@ -483,14 +524,14 @@ public class CanalController {
|
||||
}
|
||||
});
|
||||
}
|
||||
// 优先启动embeded服务
|
||||
embededCanalServer.start();
|
||||
// 优先启动embedded服务
|
||||
embeddedCanalServer.start();
|
||||
// 尝试启动一下非lazy状态的通道
|
||||
for (Map.Entry<String, InstanceConfig> entry : instanceConfigs.entrySet()) {
|
||||
final String destination = entry.getKey();
|
||||
InstanceConfig config = entry.getValue();
|
||||
// 创建destination的工作节点
|
||||
if (!embededCanalServer.isStart(destination)) {
|
||||
if (!embeddedCanalServer.isStart(destination)) {
|
||||
// HA机制启动
|
||||
ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(destination);
|
||||
if (!config.getLazy() && !runningMonitor.isStart()) {
|
||||
@@ -560,8 +601,8 @@ public class CanalController {
|
||||
ZkClientx.clearClients();
|
||||
|
||||
// 需要释放 CanalServerWithEmbedded 否则主线程退出后,进程无法自动完整退出...
|
||||
if (embededCanalServer != null) {
|
||||
embededCanalServer.stop();
|
||||
if (embeddedCanalServer != null) {
|
||||
embeddedCanalServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ public class CanalStarter {
|
||||
|
||||
if (canalMQProducer != null) {
|
||||
canalMQStarter = new CanalMQStarter(canalMQProducer);
|
||||
String destinations = CanalController.getProperty(properties, CanalConstants.CANAL_DESTINATIONS);
|
||||
String destinations = CanalController.getDestinations(properties);
|
||||
canalMQStarter.start(destinations);
|
||||
controller.setCanalMQStarter(canalMQStarter);
|
||||
}
|
||||
|
||||
@@ -177,6 +177,7 @@ rabbitmq.exchange =
|
||||
rabbitmq.username =
|
||||
rabbitmq.password =
|
||||
rabbitmq.deliveryMode =
|
||||
rabbitmq.queue =
|
||||
|
||||
|
||||
##################################################
|
||||
|
||||
@@ -56,4 +56,7 @@ canal.mq.partition=0
|
||||
#canal.mq.partitionsNum=3
|
||||
#canal.mq.dynamicTopicPartitionNum=test.*:4,mycanal:6
|
||||
#canal.mq.partitionHash=test.table:id^name,.*\\..*
|
||||
#
|
||||
# multi stream for polardbx
|
||||
canal.instance.multi.stream.on=false
|
||||
#################################################
|
||||
|
||||
@@ -185,6 +185,9 @@
|
||||
<!--表结构相关-->
|
||||
<property name="enableTsdb" value="${canal.instance.tsdb.enable:true}"/>
|
||||
<property name="tsdbSpringXml" value="${canal.instance.tsdb.spring.xml:}"/>
|
||||
<property name="tsdbJdbcUrl" value="${canal.instance.tsdb.url:}"/>
|
||||
<property name="tsdbJdbcUserName" value="${canal.instance.tsdb.dbUsername:}"/>
|
||||
<property name="tsdbJdbcPassword" value="${canal.instance.tsdb.dbPassword:}"/>
|
||||
<property name="tsdbSnapshotInterval" value="${canal.instance.tsdb.snapshot.interval:24}" />
|
||||
<property name="tsdbSnapshotExpire" value="${canal.instance.tsdb.snapshot.expire:360}" />
|
||||
|
||||
@@ -197,6 +200,7 @@
|
||||
<property name="parallelBufferSize" value="${canal.instance.parser.parallelBufferSize:256}" />
|
||||
|
||||
<property name="autoResetLatestPosMode" value="${canal.auto.reset.latest.pos.mode:false}" />
|
||||
<property name="multiStreamEnable" value="${canal.instance.multi.stream.on:false}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="mqConfig" class="com.alibaba.otter.canal.instance.core.CanalMQConfig">
|
||||
|
||||
@@ -171,6 +171,9 @@
|
||||
<!--表结构相关-->
|
||||
<property name="enableTsdb" value="${canal.instance.tsdb.enable:true}"/>
|
||||
<property name="tsdbSpringXml" value="${canal.instance.tsdb.spring.xml:}"/>
|
||||
<property name="tsdbJdbcUrl" value="${canal.instance.tsdb.url:}"/>
|
||||
<property name="tsdbJdbcUserName" value="${canal.instance.tsdb.dbUsername:}"/>
|
||||
<property name="tsdbJdbcPassword" value="${canal.instance.tsdb.dbPassword:}"/>
|
||||
<property name="tsdbSnapshotInterval" value="${canal.instance.tsdb.snapshot.interval:24}" />
|
||||
<property name="tsdbSnapshotExpire" value="${canal.instance.tsdb.snapshot.expire:360}" />
|
||||
|
||||
@@ -183,6 +186,7 @@
|
||||
<property name="parallelBufferSize" value="${canal.instance.parser.parallelBufferSize:256}" />
|
||||
|
||||
<property name="autoResetLatestPosMode" value="${canal.auto.reset.latest.pos.mode:false}" />
|
||||
<property name="multiStreamEnable" value="${canal.instance.multi.stream.on:false}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="mqConfig" class="com.alibaba.otter.canal.instance.core.CanalMQConfig">
|
||||
|
||||
@@ -170,6 +170,7 @@
|
||||
<property name="parallelBufferSize" value="${canal.instance.parser.parallelBufferSize:256}" />
|
||||
|
||||
<property name="autoResetLatestPosMode" value="${canal.auto.reset.latest.pos.mode:false}" />
|
||||
<property name="multiStreamEnable" value="${canal.instance.multi.stream.on:false}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="eventParser2" parent="baseEventParser">
|
||||
@@ -278,6 +279,7 @@
|
||||
<property name="parallelBufferSize" value="${canal.instance.parser.parallelBufferSize:256}" />
|
||||
|
||||
<property name="autoResetLatestPosMode" value="${canal.auto.reset.latest.pos.mode:false}" />
|
||||
<property name="multiStreamEnable" value="${canal.instance.multi.stream.on:false}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="mqConfig" class="com.alibaba.otter.canal.instance.core.CanalMQConfig">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user