diff --git a/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ES8xTemplate.java b/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ES8xTemplate.java index 7f125b7e..90225747 100644 --- a/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ES8xTemplate.java +++ b/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ES8xTemplate.java @@ -65,8 +65,9 @@ public class ES8xTemplate implements ESTemplate { 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); + ESUpdateRequest updateRequest = esConnection.new ES8xUpdateRequest(mapping.getIndex(), pkVal.toString()) + .setDoc(esFieldData) + .setDocAsUpsert(true); if (StringUtils.isNotEmpty(parentVal)) { updateRequest.setRouting(parentVal); } diff --git a/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ESConnection.java b/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ESConnection.java index 1037d62c..af2bbdc8 100644 --- a/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ESConnection.java +++ b/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ESConnection.java @@ -1,6 +1,21 @@ package com.alibaba.otter.canal.client.adapter.es8x.support; -import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.util.Arrays; +import java.util.Map; + +import javax.net.ssl.SSLContext; + import org.apache.commons.lang.StringUtils; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; @@ -32,20 +47,7 @@ import org.elasticsearch.search.builder.SearchSourceBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.net.ssl.SSLContext; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.KeyStore; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.util.Arrays; -import java.util.Map; +import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest; /** * ES 连接器, 只支持 Rest 方式 @@ -59,7 +61,7 @@ public class ESConnection { private RestHighLevelClient restHighLevelClient; - public ESConnection(String[] hosts, Map properties) throws UnknownHostException { + public ESConnection(String[] hosts, Map properties) throws UnknownHostException{ String caPath = properties.get("security.ca.path"); if (StringUtils.isNotEmpty(caPath)) { connectEsWithCa(hosts, properties, caPath); @@ -67,6 +69,7 @@ public class ESConnection { connectEsWithoutCa(hosts, properties); } } + private void connectEsWithCa(String[] hosts, Map properties, String caPath) { Path caCertificatePath = Paths.get(caPath); try (InputStream is = Files.newInputStream(caCertificatePath)) { @@ -75,8 +78,7 @@ public class ESConnection { KeyStore trustStore = KeyStore.getInstance("pkcs12"); trustStore.load(null, null); trustStore.setCertificateEntry("ca", trustedCa); - SSLContextBuilder sslContextBuilder = SSLContexts.custom() - .loadTrustMaterial(trustStore, null); + SSLContextBuilder sslContextBuilder = SSLContexts.custom().loadTrustMaterial(trustStore, null); final SSLContext sslContext = sslContextBuilder.build(); HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new); @@ -86,13 +88,15 @@ public class ESConnection { String[] nameAndPwdArr = nameAndPwd.split(":"); final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, - new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1])); + new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1])); restClientBuilder.setHttpClientConfigCallback(httpClientBuilder -> { httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); return httpClientBuilder.setSSLContext(sslContext); }); } - restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build()).setApiCompatibilityMode(true).build(); + restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build()) + .setApiCompatibilityMode(true) + .build(); } catch (Exception e) { throw new RuntimeException(e); } @@ -106,12 +110,12 @@ public class ESConnection { String[] nameAndPwdArr = nameAndPwd.split(":"); final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, - new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1])); + new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1])); restClientBuilder.setHttpClientConfigCallback( - httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)); + httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)); } restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build()).setApiCompatibilityMode(true) - .build(); + .build(); } public void close() { @@ -147,9 +151,9 @@ public class ESConnection { private IndexRequestBuilder indexRequestBuilder; - private IndexRequest indexRequest; + private IndexRequest indexRequest; - public ES8xIndexRequest(String index, String id) { + public ES8xIndexRequest(String index, String id){ indexRequest = new IndexRequest(index); indexRequest.id(id); @@ -190,9 +194,9 @@ public class ESConnection { private UpdateRequestBuilder updateRequestBuilder; - private UpdateRequest updateRequest; + private UpdateRequest updateRequest; - public ES8xUpdateRequest(String index, String id) { + public ES8xUpdateRequest(String index, String id){ updateRequest = new UpdateRequest(index, id); } @@ -239,9 +243,9 @@ public class ESConnection { private DeleteRequestBuilder deleteRequestBuilder; - private DeleteRequest deleteRequest; + private DeleteRequest deleteRequest; - public ES8xDeleteRequest(String index, String id) { + public ES8xDeleteRequest(String index, String id){ deleteRequest = new DeleteRequest(index, id); @@ -268,11 +272,11 @@ public class ESConnection { private SearchRequestBuilder searchRequestBuilder; - private SearchRequest searchRequest; + private SearchRequest searchRequest; - private SearchSourceBuilder sourceBuilder; + private SearchSourceBuilder sourceBuilder; - public ESSearchRequest(String index) { + public ESSearchRequest(String index){ searchRequest = new SearchRequest(index); sourceBuilder = new SearchSourceBuilder(); @@ -325,12 +329,10 @@ public class ESConnection { private BulkRequestBuilder bulkRequestBuilder; - private BulkRequest bulkRequest; - - public ES8xBulkRequest() { + private BulkRequest bulkRequest; + public ES8xBulkRequest(){ bulkRequest = new BulkRequest(); - } public void resetBulk() { @@ -398,7 +400,7 @@ public class ESConnection { private BulkResponse bulkResponse; - public ES8xBulkResponse(BulkResponse bulkResponse) { + public ES8xBulkResponse(BulkResponse bulkResponse){ this.bulkResponse = bulkResponse; } @@ -438,7 +440,7 @@ public class ESConnection { } try { return HttpHost.create(new URI(uri - .getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment()) + .getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment()) .toString()); } catch (URISyntaxException ex) { throw new IllegalStateException(ex); diff --git a/client/src/main/java/com/alibaba/otter/canal/client/pulsarmq/PulsarMQCanalConnector.java b/client/src/main/java/com/alibaba/otter/canal/client/pulsarmq/PulsarMQCanalConnector.java index 2fbc0aa7..cc3e4f51 100644 --- a/client/src/main/java/com/alibaba/otter/canal/client/pulsarmq/PulsarMQCanalConnector.java +++ b/client/src/main/java/com/alibaba/otter/canal/client/pulsarmq/PulsarMQCanalConnector.java @@ -25,97 +25,98 @@ import com.google.common.collect.Lists; * 注意点: * 1. 相比于canal {@linkplain SimpleCanalConnector}, 这里get和ack操作不能有并发, 必须是一个线程执行get后,内存里执行完毕ack后再取下一个get * + * * todo 重复消费的概率相当高。一次批处理中,只要有一个消息处理失败,则该批次全部重试 * * @since 1.1.1 */ public class PulsarMQCanalConnector implements CanalMQConnector { - private static final Logger logger = LoggerFactory.getLogger(PulsarMQCanalConnector.class); + private static final Logger logger = LoggerFactory + .getLogger(PulsarMQCanalConnector.class); private volatile Messages lastGetBatchMessage; /** * 连接pulsar客户端 */ - private PulsarClient pulsarClient; + private PulsarClient pulsarClient; /** * 消费者 */ - private Consumer consumer; + private Consumer consumer; /** * 是否扁平化Canal消息内容 */ - private boolean isFlatMessage = false; + private boolean isFlatMessage = false; /** * 主题名称 */ - private String topic; + private String topic; /** * 环境连接URL */ - private String serviceUrl; + private String serviceUrl; /** * 角色认证token */ - private String roleToken; + private String roleToken; /** * listener name */ - private String listenerName; + private String listenerName; /** * 订阅客户端名称 */ - private String subscriptName; + private String subscriptName; /** * 每次批量获取数据的最大条目数,默认30 */ - private int batchSize = 30; + private int batchSize = 30; /** - * 与{@code batchSize}一起决定批量获取的数据大小 - * 当: + * 与{@code batchSize}一起决定批量获取的数据大小 当: *

* 1. {@code batchSize} 条消息未消费时
* 2. 距上一次批量消费时间达到{@code batchTimeoutSeconds}秒时 *

* 任一条件满足,即执行批量消费 */ - private int getBatchTimeoutSeconds = 30; + private int getBatchTimeoutSeconds = 30; /** * 批量处理消息时,一次批量处理的超时时间秒数 *

* 该时间应该根据{@code batchSize}和{@code batchTimeoutSeconds}合理设置 *

*/ - private int batchProcessTimeoutSeconds = 60; + private int batchProcessTimeoutSeconds = 60; /** * 消费失败后的重试秒数,默认60秒 */ - private int redeliveryDelaySeconds = 60; + private int redeliveryDelaySeconds = 60; /** * 当客户端接收到消息,30秒还没有返回ack给服务端时,ack超时,会重新消费该消息 */ - private int ackTimeoutSeconds = 30; + private int ackTimeoutSeconds = 30; /** * 是否开启消息失败重试功能,默认开启 */ - private boolean isRetry = true; + private boolean isRetry = true; /** *

* true重试(-RETRY)和死信队列(-DLQ)后缀为大写,有些地方创建的为小写,需确保正确 *

*/ - private boolean isRetryDLQUpperCase = false; + private boolean isRetryDLQUpperCase = false; /** * 最大重试次数 */ - private int maxRedeliveryCount = 128; + private int maxRedeliveryCount = 128; /** * 连接标识位,在连接或关闭连接后改变值 */ - private boolean connected = false; + private boolean connected = false; /** * 除必要参数外,其他参数使用默认值 @@ -125,21 +126,21 @@ public class PulsarMQCanalConnector implements CanalMQConnector { *

* * @param isFlatMessage true使用扁平消息 - * @param serviceUrl pulsar服务连接地址,通常为:pulsar:host:ip或http://host:ip - * @param roleToken 有对应topic的消费者权限的角色token - * @param topic 订阅主题 + * @param serviceUrl pulsar服务连接地址,通常为:pulsar:host:ip或http://host:ip + * @param roleToken 有对应topic的消费者权限的角色token + * @param topic 订阅主题 * @param subscriptName 订阅和客户端名称,同一个订阅名视为同一个消费实例 * @date 2021/9/18 08:54 * @author chad * @since 1 by chad at 2021/9/18 完善 */ - public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic - , String subscriptName) { - this(isFlatMessage, serviceUrl, roleToken, topic, subscriptName,null); + public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic, + String subscriptName){ + this(isFlatMessage, serviceUrl, roleToken, topic, subscriptName, null); } - public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic - , String subscriptName, String listenerName) { + public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic, + String subscriptName, String listenerName){ this.isFlatMessage = isFlatMessage; this.serviceUrl = serviceUrl; this.roleToken = roleToken; @@ -158,19 +159,31 @@ public class PulsarMQCanalConnector implements CanalMQConnector { * @author chad * @since 1 by chad at 2021/9/18 完善 */ - public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic - , String subscriptName, int batchSize, int getBatchTimeoutSeconds, int batchProcessTimeoutSeconds - , int redeliveryDelaySeconds, int ackTimeoutSeconds, boolean isRetry, boolean isRetryDLQUpperCase - , int maxRedeliveryCount) { - this(isFlatMessage, serviceUrl, roleToken, topic, subscriptName, batchSize, getBatchTimeoutSeconds - , batchProcessTimeoutSeconds, redeliveryDelaySeconds, ackTimeoutSeconds, isRetry, isRetryDLQUpperCase - , maxRedeliveryCount, null); + public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic, + String subscriptName, int batchSize, int getBatchTimeoutSeconds, + int batchProcessTimeoutSeconds, int redeliveryDelaySeconds, int ackTimeoutSeconds, + boolean isRetry, boolean isRetryDLQUpperCase, int maxRedeliveryCount){ + this(isFlatMessage, + serviceUrl, + roleToken, + topic, + subscriptName, + batchSize, + getBatchTimeoutSeconds, + batchProcessTimeoutSeconds, + redeliveryDelaySeconds, + ackTimeoutSeconds, + isRetry, + isRetryDLQUpperCase, + maxRedeliveryCount, + null); } - public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic - , String subscriptName, int batchSize, int getBatchTimeoutSeconds, int batchProcessTimeoutSeconds - , int redeliveryDelaySeconds, int ackTimeoutSeconds, boolean isRetry, boolean isRetryDLQUpperCase - , int maxRedeliveryCount, String listenerName) { + public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic, + String subscriptName, int batchSize, int getBatchTimeoutSeconds, + int batchProcessTimeoutSeconds, int redeliveryDelaySeconds, int ackTimeoutSeconds, + boolean isRetry, boolean isRetryDLQUpperCase, int maxRedeliveryCount, + String listenerName){ this.isFlatMessage = isFlatMessage; this.serviceUrl = serviceUrl; this.roleToken = roleToken; @@ -195,13 +208,12 @@ public class PulsarMQCanalConnector implements CanalMQConnector { // 连接创建客户端 try { ClientBuilder builder = PulsarClient.builder() - .serviceUrl(serviceUrl) - .authentication(AuthenticationFactory.token(roleToken)); + .serviceUrl(serviceUrl) + .authentication(AuthenticationFactory.token(roleToken)); if (StringUtils.isNotEmpty(listenerName)) { builder.listenerName(listenerName); } - pulsarClient = builder - .build(); + pulsarClient = builder.build(); } catch (PulsarClientException e) { throw new RuntimeException(e); } @@ -250,15 +262,14 @@ public class PulsarMQCanalConnector implements CanalMQConnector { builder.subscriptionType(SubscriptionType.Failover); builder - // 调用consumer.negativeAcknowledge(message) (即nack)来表示消费失败的消息 - // 在指定的时间进行重新消费,默认是1分钟。 - .negativeAckRedeliveryDelay(this.redeliveryDelaySeconds, TimeUnit.SECONDS) - .subscriptionName(this.subscriptName) - ; + // 调用consumer.negativeAcknowledge(message) (即nack)来表示消费失败的消息 + // 在指定的时间进行重新消费,默认是1分钟。 + .negativeAckRedeliveryDelay(this.redeliveryDelaySeconds, TimeUnit.SECONDS) + .subscriptionName(this.subscriptName); if (this.isRetry) { DeadLetterPolicy.DeadLetterPolicyBuilder dlqBuilder = DeadLetterPolicy.builder() - // 最大重试次数 - .maxRedeliverCount(this.maxRedeliveryCount); + // 最大重试次数 + .maxRedeliverCount(this.maxRedeliveryCount); // 指定重试队列,不是多个或通配符topic才能判断重试队列 if (!MQUtil.isPatternTag(this.topic)) { String retryTopic = this.topic + (this.isRetryDLQUpperCase ? "-RETRY" : "-retry"); @@ -267,19 +278,17 @@ public class PulsarMQCanalConnector implements CanalMQConnector { dlqBuilder.deadLetterTopic(dlqTopic); } - //默认关闭,如果需要重试则开启 - builder.enableRetry(true) - .deadLetterPolicy(dlqBuilder.build()); + // 默认关闭,如果需要重试则开启 + builder.enableRetry(true).deadLetterPolicy(dlqBuilder.build()); } // ack超时 builder.ackTimeout(this.ackTimeoutSeconds, TimeUnit.SECONDS); // pulsar批量获取消息设置 - builder.batchReceivePolicy(new BatchReceivePolicy.Builder() - .maxNumMessages(this.batchSize) - .timeout(this.getBatchTimeoutSeconds, TimeUnit.SECONDS) - .build()); + builder.batchReceivePolicy(new BatchReceivePolicy.Builder().maxNumMessages(this.batchSize) + .timeout(this.getBatchTimeoutSeconds, TimeUnit.SECONDS) + .build()); try { this.consumer = builder.subscribe(); @@ -289,7 +298,6 @@ public class PulsarMQCanalConnector implements CanalMQConnector { } } - @Override public void subscribe() throws CanalClientException { this.subscribe(null); @@ -310,7 +318,7 @@ public class PulsarMQCanalConnector implements CanalMQConnector { * 不关注业务执行结果,只要收到消息即认识消费成功,自动ack * * @param timeout 阻塞获取消息的超时时间 - * @param unit 时间单位 + * @param unit 时间单位 * @return java.util.List * @date 2021/9/13 22:24 * @author chad @@ -326,13 +334,14 @@ public class PulsarMQCanalConnector implements CanalMQConnector { } /** - * 关心业务执行结果,业务侧根据执行结果调用 {@link PulsarMQCanalConnector#ack()}或{@link PulsarMQCanalConnector#rollback()} + * 关心业务执行结果,业务侧根据执行结果调用 + * {@link PulsarMQCanalConnector#ack()}或{@link PulsarMQCanalConnector#rollback()} *

* 本方法示支持多线程,在MQ保障顺序的前提下,也无法提供单Topic多线程 *

* * @param timeout 阻塞获取消息的超时时间 - * @param unit 时间单位 + * @param unit 时间单位 * @return java.util.List * @date 2021/9/13 22:26 * @author chad @@ -366,7 +375,8 @@ public class PulsarMQCanalConnector implements CanalMQConnector { * @return java.util.List * @date 2021/9/14 15:20 * @author chad - * @since 1 by chad at 2021/9/14 供{@link PulsarMQCanalConnector#getListWithoutAck(Long, TimeUnit)} + * @since 1 by chad at 2021/9/14 + * 供{@link PulsarMQCanalConnector#getListWithoutAck(Long, TimeUnit)} * 和{@link PulsarMQCanalConnector#getFlatListWithoutAck(Long, TimeUnit)}调用 */ private List getListWithoutAck() { diff --git a/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/config/PulsarMQConstants.java b/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/config/PulsarMQConstants.java index e04afee4..5a6d1774 100644 --- a/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/config/PulsarMQConstants.java +++ b/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/config/PulsarMQConstants.java @@ -64,6 +64,6 @@ public class PulsarMQConstants { /** * Pulsar admin服务器地址 */ - public static final String PULSARMQ_LISTENER_NAME = ROOT + "." + "listenerName"; + public static final String PULSARMQ_LISTENER_NAME = ROOT + "." + "listenerName"; } diff --git a/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/consumer/CanalPulsarMQConsumer.java b/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/consumer/CanalPulsarMQConsumer.java index 1f361204..ad178d9b 100644 --- a/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/consumer/CanalPulsarMQConsumer.java +++ b/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/consumer/CanalPulsarMQConsumer.java @@ -56,7 +56,7 @@ public class CanalPulsarMQConsumer implements CanalMsgConsumer { private String roleToken; /** - * listener name + * listener name */ private String listenerName; diff --git a/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/producer/CanalPulsarMQProducer.java b/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/producer/CanalPulsarMQProducer.java index 0a50f285..8347710a 100644 --- a/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/producer/CanalPulsarMQProducer.java +++ b/connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/producer/CanalPulsarMQProducer.java @@ -74,7 +74,7 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ builder.authentication(AuthenticationFactory.token(pulsarMQProducerConfig.getRoleToken())); } if (StringUtils.isNotEmpty(pulsarMQProducerConfig.getListenerName())) { - //listener name + // listener name builder.listenerName(pulsarMQProducerConfig.getListenerName()); } diff --git a/dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/JsonConversion.java b/dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/JsonConversion.java index 61fe9bc6..7dd92e65 100644 --- a/dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/JsonConversion.java +++ b/dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/JsonConversion.java @@ -1,10 +1,8 @@ package com.taobao.tddl.dbsync.binlog; -import java.nio.charset.Charset; +import static com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.*; -import static com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.appendNumber2; -import static com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.appendNumber4; -import static com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.usecondsToStr; +import java.nio.charset.Charset; /** * 处理下MySQL json二进制转化为可读的字符串 @@ -34,26 +32,25 @@ public class JsonConversion { public static final char JSONB_FALSE_LITERAL = '\2'; /* - * The size of offset or size fields in the small and the large storage - * format for JSON objects and JSON arrays. + * The size of offset or size fields in the small and the large storage format + * for JSON objects and JSON arrays. */ public static final int SMALL_OFFSET_SIZE = 2; public static final int LARGE_OFFSET_SIZE = 4; /* - * The size of key entries for objects when using the small storage format - * or the large storage format. In the small format it is 4 bytes (2 bytes - * for key length and 2 bytes for key offset). In the large format it is 6 - * (2 bytes for length, 4 bytes for offset). + * The size of key entries for objects when using the small storage format or + * the large storage format. In the small format it is 4 bytes (2 bytes for key + * length and 2 bytes for key offset). In the large format it is 6 (2 bytes for + * length, 4 bytes for offset). */ public static final int KEY_ENTRY_SIZE_SMALL = (2 + SMALL_OFFSET_SIZE); public static final int KEY_ENTRY_SIZE_LARGE = (2 + LARGE_OFFSET_SIZE); /* - * The size of value entries for objects or arrays. When using the small - * storage format, the entry size is 3 (1 byte for type, 2 bytes for - * offset). When using the large storage format, it is 5 (1 byte for type, 4 - * bytes for offset). + * The size of value entries for objects or arrays. When using the small storage + * format, the entry size is 3 (1 byte for type, 2 bytes for offset). When using + * the large storage format, it is 5 (1 byte for type, 4 bytes for offset). */ public static final int VALUE_ENTRY_SIZE_SMALL = (1 + SMALL_OFFSET_SIZE); public static final int VALUE_ENTRY_SIZE_LARGE = (1 + LARGE_OFFSET_SIZE); @@ -160,13 +157,12 @@ public class JsonConversion { if (len < n + str_len) { throw new IllegalArgumentException("illegal json data"); } - return new Json_Value(Json_enum_type.STRING, buffer.rewind() - .forward((int) n) - .getFixString((int) str_len, charset)); + return new Json_Value(Json_enum_type.STRING, + buffer.rewind().forward((int) n).getFixString((int) str_len, charset)); case JSONB_TYPE_OPAQUE: /* - * There should always be at least one byte, which tells the - * field type of the opaque value. + * There should always be at least one byte, which tells the field type of the + * opaque value. */ // The type is encoded as a uint8 that maps to an // enum_field_types. @@ -368,45 +364,45 @@ public class JsonConversion { buf.append('"').append(text).append('"'); } else if (m_field_type == LogEvent.MYSQL_TYPE_DATE || m_field_type == LogEvent.MYSQL_TYPE_DATETIME || m_field_type == LogEvent.MYSQL_TYPE_TIMESTAMP) { - long packed_value = m_data.getLong64(); - if (packed_value == 0) { - text = "0000-00-00 00:00:00"; - } else { - // 构造TimeStamp只处理到秒 - long ultime = Math.abs(packed_value); - long intpart = ultime >> 24; - int frac = (int) (ultime % (1L << 24)); - long ymd = intpart >> 17; - long ym = ymd >> 5; - long hms = intpart % (1 << 17); - // text = - // String.format("%04d-%02d-%02d %02d:%02d:%02d", - // (int) (ym / 13), - // (int) (ym % 13), - // (int) (ymd % (1 << 5)), - // (int) (hms >> 12), - // (int) ((hms >> 6) % (1 << 6)), - // (int) (hms % (1 << 6))); - StringBuilder builder = new StringBuilder(26); - appendNumber4(builder, (int) (ym / 13)); - builder.append('-'); - appendNumber2(builder, (int) (ym % 13)); - builder.append('-'); - appendNumber2(builder, (int) (ymd % (1 << 5))); - builder.append(' '); - appendNumber2(builder, (int) (hms >> 12)); - builder.append(':'); - appendNumber2(builder, (int) ((hms >> 6) % (1 << 6))); - builder.append(':'); - appendNumber2(builder, (int) (hms % (1 << 6))); - builder.append('.').append(usecondsToStr(frac, 6)); - text = builder.toString(); - } - buf.append('"').append(text).append('"'); - } else { - text = m_data.getFixString((int) m_length, charset); - buf.append('"').append(escapse(text)).append('"'); - } + long packed_value = m_data.getLong64(); + if (packed_value == 0) { + text = "0000-00-00 00:00:00"; + } else { + // 构造TimeStamp只处理到秒 + long ultime = Math.abs(packed_value); + long intpart = ultime >> 24; + int frac = (int) (ultime % (1L << 24)); + long ymd = intpart >> 17; + long ym = ymd >> 5; + long hms = intpart % (1 << 17); + // text = + // String.format("%04d-%02d-%02d %02d:%02d:%02d", + // (int) (ym / 13), + // (int) (ym % 13), + // (int) (ymd % (1 << 5)), + // (int) (hms >> 12), + // (int) ((hms >> 6) % (1 << 6)), + // (int) (hms % (1 << 6))); + StringBuilder builder = new StringBuilder(26); + appendNumber4(builder, (int) (ym / 13)); + builder.append('-'); + appendNumber2(builder, (int) (ym % 13)); + builder.append('-'); + appendNumber2(builder, (int) (ymd % (1 << 5))); + builder.append(' '); + appendNumber2(builder, (int) (hms >> 12)); + builder.append(':'); + appendNumber2(builder, (int) ((hms >> 6) % (1 << 6))); + builder.append(':'); + appendNumber2(builder, (int) (hms % (1 << 6))); + builder.append('.').append(usecondsToStr(frac, 6)); + text = builder.toString(); + } + buf.append('"').append(text).append('"'); + } else { + text = m_data.getFixString((int) m_length, charset); + buf.append('"').append(escapse(text)).append('"'); + } break; case STRING: @@ -452,7 +448,8 @@ public class JsonConversion { } public static enum Json_enum_type { - OBJECT, ARRAY, STRING, INT, UINT, DOUBLE, LITERAL_NULL, LITERAL_TRUE, LITERAL_FALSE, OPAQUE, ERROR + OBJECT, ARRAY, STRING, INT, UINT, DOUBLE, LITERAL_NULL, LITERAL_TRUE, + LITERAL_FALSE, OPAQUE, ERROR } } diff --git a/dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/JsonConversion_Json_ValueTest.java b/dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/JsonConversion_Json_ValueTest.java index f1c72d04..3f8b8d65 100644 --- a/dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/JsonConversion_Json_ValueTest.java +++ b/dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/JsonConversion_Json_ValueTest.java @@ -1,5 +1,7 @@ package com.taobao.tddl.dbsync.binlog; +import java.nio.charset.Charset; + import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -9,8 +11,6 @@ import org.junit.rules.Timeout; import com.taobao.tddl.dbsync.binlog.JsonConversion.Json_Value; import com.taobao.tddl.dbsync.binlog.JsonConversion.Json_enum_type; -import java.nio.charset.Charset; - public class JsonConversion_Json_ValueTest { @Rule @@ -50,7 +50,6 @@ public class JsonConversion_Json_ValueTest { // Act thrown.expect(IllegalArgumentException.class); JsonConversion.parse_value(type, buffer, len, charsetName); - // Method is not expected to return due to exception thrown } @@ -60,7 +59,10 @@ public class JsonConversion_Json_ValueTest { // {"internal_uri_rewrite": {"(.*)(/[^/]+\\.(mp|MP)4)$": "$1/mp4$2"}} String jsonData = "{\"internal_uri_rewrite\": {\"(.*)(/[^/]+\\\\.(mp|MP)4)$\": \"$1/mp4$2\"}}"; - byte[] data = new byte[]{1, 0, 74, 0, 11, 0, 20, 0, 0, 31, 0, 105, 110, 116, 101, 114, 110, 97, 108, 95, 117, 114, 105, 95, 114, 101, 119, 114, 105, 116, 101, 1, 0, 43, 0, 11, 0, 23, 0, 12, 34, 0, 40, 46, 42, 41, 40, 47, 91, 94, 47, 93, 43, 92, 46, 40, 109, 112, 124, 77, 80, 41, 52, 41, 36, 8, 36, 49, 47, 109, 112, 52, 36, 50}; + byte[] data = new byte[] { 1, 0, 74, 0, 11, 0, 20, 0, 0, 31, 0, 105, 110, 116, 101, 114, 110, 97, 108, 95, 117, + 114, 105, 95, 114, 101, 119, 114, 105, 116, 101, 1, 0, 43, 0, 11, 0, 23, 0, 12, 34, + 0, 40, 46, 42, 41, 40, 47, 91, 94, 47, 93, 43, 92, 46, 40, 109, 112, 124, 77, 80, 41, + 52, 41, 36, 8, 36, 49, 47, 109, 112, 52, 36, 50 }; final LogBuffer buffer = new LogBuffer(data, 0, 74); Charset charset = Charset.forName("UTF-8"); @@ -68,7 +70,6 @@ public class JsonConversion_Json_ValueTest { StringBuilder builder = new StringBuilder(); jsonValue.toJsonString(builder, charset); - Assert.assertEquals(builder.toString(), jsonData); Assert.assertEquals(jsonValue.key(0, charset), "internal_uri_rewrite");