
com.huaweicloud.dws.client.binlog.collector.BinlogApi Maven / Gradle / Ivy
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
*/
package com.huaweicloud.dws.client.binlog.collector;
import com.huaweicloud.dws.client.TableConfig;
import com.huaweicloud.dws.client.binlog.model.BinlogRecord;
import com.huaweicloud.dws.client.binlog.model.BinlogRecordType;
import com.huaweicloud.dws.client.binlog.model.Slot;
import com.huaweicloud.dws.client.model.Constants;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
* @ProjectName: dws-connectors
* @Description: 和内核交互的api,待与内核联调
* @Date: 2023/09/19 11:09
* @Version: 1.0
**/
@Slf4j
public class BinlogApi {
// 记录数据节点的个数,如节点个数发现变化则需要重新获取
public static final ThreadLocal NODE_COUNT = ThreadLocal.withInitial(() -> 0);
/**
* 获取同步点信息(node_name、node_id、last_sync_point、latest_sync_point):
* 1. 需要注意区分GTM和GTM-free场景,GTM场景所有dn的startCsn和endCsn都相同
* 2. 如果startCsn返回-1,这种情况就是全量同步
*
* @param connection jdbc连接信息
* @param tableName 表名
* @param slotName 槽名
* @param nodeId 获取对应dn上的同步点
* @param isCheckpoint 是否是checkpoint流程
* @param isNeedRedistribution 是否兼容扩容重分布流程
* @return 同步点信息
*/
public static List getSyncPoint(Connection connection, String tableName, String slotName, int nodeId,
boolean isCheckpoint, boolean isNeedRedistribution) throws SQLException {
String sql;
if (isNeedRedistribution) {
// 需要传入节点个数
sql = "select * from pg_catalog.pgxc_get_binlog_sync_point(?, ?, ?, ?, ?);";
} else {
sql = "select * from pg_catalog.pgxc_get_binlog_sync_point(?, ?, ?, ?);";
}
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, tableName);
statement.setString(2, slotName);
statement.setBoolean(3, isCheckpoint);
statement.setInt(4, nodeId);
if (isNeedRedistribution) {
statement.setInt(5, NODE_COUNT.get());
}
try (ResultSet resultSet = statement.executeQuery()) {
List slots = new ArrayList<>();
while (resultSet.next()) {
int dnNodeId = resultSet.getInt("node_id");
long startCsn = resultSet.getLong("last_sync_point");
long endCsn = resultSet.getLong("latest_sync_point");
long xmin = resultSet.getLong("xmin");
Slot slot = new Slot();
slot.slotDNNodeId(dnNodeId)
.startCsn(startCsn)
.currentStartCsn(startCsn)
.endCsn(endCsn)
.setXmin(xmin);
slots.add(slot);
}
// 按照dnNodeId排序返回
return slots.stream().sorted(Comparator.comparing(Slot::getDnNodeId)).collect(Collectors.toList());
}
}
}
public static String getSelectValues(List columnNames, TableConfig tableConfig) {
// 是否使用新的系统字段(注意要和内核版本匹配)
boolean newSystemValue = tableConfig.isNewSystemValue();
// 是否包含系统字段
boolean containBinlogSysValue = tableConfig.isContainBinlogSysValue();
if (containBinlogSysValue) {
// 如果包含系统字段,直接返回,即select *,不然会出现二义性
return Constants.SELECT_ALL;
}
String defaultColumns;
if (newSystemValue) {
defaultColumns = Constants.NEW_SYNC_POINT + ", " + Constants.NEW_EVENT_SEQUENCE + ", " + Constants.NEW_TYPE + ", ";
} else {
defaultColumns = Constants.OLD_SYNC_POINT + ", " + Constants.OLD_EVENT_SEQUENCE + ", " + Constants.OLD_TYPE + ", ";
}
defaultColumns += String.join(", ", columnNames);
return defaultColumns;
}
/**
* 获取binlog信息
*
* @param connection jdbc连接信息
* @param slot slot信息
* @param columnNames 需要获取哪些列信息
* @param tableConfig 表的配置信息
* @param queue 队列信息
* @param running 外部程序是否在运行(用于快速停止)
* @return 解码后的binlog信息
*/
public static int getBinlogRecords(Connection connection, Slot slot, List columnNames,
TableConfig tableConfig, BlockingQueue queue, AtomicBoolean running) throws Exception {
// 获取TableConfig中属性
int fetchSize = tableConfig.getBinlogBatchReadSize();
String tableName = tableConfig.getTableName();
// 获取slot中属性
long startCsn = slot.getCurrentStartCsn();
long endCsn = slot.getConsumeEndScn(fetchSize);
int dnNodeId = slot.getDnNodeId();
long xmin = slot.getXmin();
// 设置fetchSize得关闭自动提交
connection.setAutoCommit(false);
// 获取select的字段
String selectValues = getSelectValues(columnNames, tableConfig);
// 参数: tableName、dnNodeId、startCsn、endScn
String sql = String.format(Locale.ROOT, "select %s from pg_catalog.pgxc_get_binlog_changes('%s', ?, ?, ?) order by 1,2;",
selectValues, tableName);
long start = System.currentTimeMillis();
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setFetchSize(fetchSize);
statement.setInt(1, dnNodeId);
statement.setLong(2, startCsn);
statement.setLong(3, endCsn);
try (ResultSet resultSet = statement.executeQuery()) {
long end = System.currentTimeMillis();
int size = 0;
// 按照fetchSize循环读取
while (resultSet.next() && running.get()) {
long syncPoint = resultSet.getLong(Constants.SYNC_POINT_IDX);
int typeIdx = Constants.TYPE_IDX;
String type = resultSet.getString(typeIdx);
BinlogRecord binlogRecord = new BinlogRecord();
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy