
com.alibaba.hologres.client.Subscribe Maven / Gradle / Ivy
/*
* Copyright (c) 2022. Alibaba Group Holding Limited
*/
package com.alibaba.hologres.client;
import com.alibaba.hologres.client.exception.ExceptionCode;
import com.alibaba.hologres.client.exception.HoloClientException;
import com.alibaba.hologres.client.impl.binlog.BinlogOffset;
import com.alibaba.hologres.client.utils.IdentifierUtil;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
/**
* 消费binlog的请求.
*/
public class Subscribe {
private final String tableName;
private final String slotName;
//两个builder会确保offsetMap和startTime
private final Map offsetMap;
private final String binlogReadStartTime;
// tableName是分区父表时,分区子表的消费请求
private final NavigableMap partitionToSubscribeMap;
// STATIC模式, 指定希望消费的分区的分区值,字符串数组
private String[] partitionValues;
private String[] logicalPartitionColumnNames;
private String[][] logicalPartitionValues;
protected Subscribe(String tableName, String slotName, Map offsetMap, String binlogReadStartTime) {
this(tableName, slotName, offsetMap, binlogReadStartTime, new TreeMap<>(), new String[0]);
}
protected Subscribe(String tableName, String slotName, Map offsetMap, String binlogReadStartTime,
NavigableMap partitionToSubscribeMap, String[] partitionValues) {
this.tableName = tableName;
this.slotName = slotName;
this.offsetMap = offsetMap;
this.binlogReadStartTime = binlogReadStartTime;
this.partitionToSubscribeMap = partitionToSubscribeMap;
this.partitionValues = partitionValues;
}
protected Subscribe(String tableName, String slotName, Map offsetMap, String binlogReadStartTime,
NavigableMap partitionToSubscribeMap, String[] logicalPartitionNames, String[][] logicalPartitionValues) {
this.tableName = tableName;
this.slotName = slotName;
this.offsetMap = offsetMap;
this.binlogReadStartTime = binlogReadStartTime;
this.partitionToSubscribeMap = partitionToSubscribeMap;
this.logicalPartitionColumnNames = logicalPartitionNames;
this.logicalPartitionValues = logicalPartitionValues;
}
public String getTableName() {
return tableName;
}
public String getSlotName() {
return slotName;
}
public Map getOffsetMap() {
return offsetMap;
}
public String getBinlogReadStartTime() {
return binlogReadStartTime;
}
public NavigableMap getPartitionToSubscribeMap() {
return partitionToSubscribeMap;
}
public String[] getPartitionValuesToSubscribe() {
return partitionValues;
}
public void setLogicalPartitionValuesToSubscribe(String[][] logicalPartitionValues) {
this.logicalPartitionValues = logicalPartitionValues;
}
// Encode the logical_partition_values 2d array into a string.
// The first level of the array represents each row and is delimited by colons.
// The second level represents each column in the same row and is delimited by commas.
public String encodeLogicalPartitionValuesToSubscribe() throws HoloClientException {
if (logicalPartitionValues == null) {
return null;
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < logicalPartitionValues.length; i++) {
if (logicalPartitionValues[0].length != logicalPartitionValues[i].length) {
throw new HoloClientException(ExceptionCode.INVALID_REQUEST, "Each row in partition-values-to-read should have the same column number");
}
for (int j = 0; j < logicalPartitionValues[i].length; j++) {
if (j > 0) {
builder.append(",");
}
builder.append(IdentifierUtil.quoteIdentifier(logicalPartitionValues[i][j], true, true));
}
if (i < logicalPartitionValues.length - 1) {
builder.append(";");
}
}
return builder.toString();
}
public void setLogicalPartitionColumnNamesToSubscribe(String[] logicalPartitionColumnNames) {
this.logicalPartitionColumnNames = logicalPartitionColumnNames;
}
// Encode the logical_partition_column_names array into a string delimited by commas.
public String encodeLogicalPartitionColumnNamesToSubscribe() {
if (logicalPartitionColumnNames == null) {
return null;
}
StringBuilder builder = new StringBuilder();
// Iterating through the array and building the quoted column names
for (int i = 0; i < logicalPartitionColumnNames.length; i++) {
if (i > 0) {
builder.append(",");
}
builder.append(IdentifierUtil.quoteIdentifier(logicalPartitionColumnNames[i], true, true)); // Assuming quoteIdentifier is a method in the same class
}
return builder.toString();
}
@Override
public String toString() {
return "Subscribe{" +
"tableName='" + tableName + '\'' +
", slotName='" + slotName + '\'' +
", offsetMap=" + offsetMap +
", binlogReadStartTime='" + binlogReadStartTime + '\'' +
", partitionToSubscribeMap=" + partitionToSubscribeMap +
", logicalPartitionColumnNames=" + logicalPartitionColumnNames +
", logicalPartitionValues=" + logicalPartitionValues +
'}';
}
public static OffsetBuilder newOffsetBuilder(String tableName) {
return new OffsetBuilder(tableName);
}
public static OffsetBuilder newOffsetBuilder(String tableName, String slotName) {
return new OffsetBuilder(tableName, slotName);
}
public static StartTimeBuilder newStartTimeBuilder(String tableName, String slotName) {
return new StartTimeBuilder(tableName, slotName);
}
public static StartTimeBuilder newStartTimeBuilder(String tableName) {
return new StartTimeBuilder(tableName);
}
/**
* Builder.
*/
public abstract static class Builder {
protected final String tableName;
protected final String slotName;
public Builder(String tableName) {
if (tableName == null) {
throw new InvalidParameterException("tableName must be not null");
}
this.tableName = tableName;
this.slotName = null;
}
public Builder(String tableName, String slotName) {
if (tableName == null) {
throw new InvalidParameterException("tableName must be not null");
}
this.tableName = tableName;
this.slotName = slotName;
}
}
/**
* 指定shard时用的.
*/
public static class OffsetBuilder extends Builder {
private Map offsetMap;
private Map partitionToBuilderMap;
private List partitionValuesToSubscribe = new ArrayList<>();
private String[] logicalPartitionNamesToSubscribe;
private String[][] logicalPartitionValuesToSubscribe;
public OffsetBuilder(String tableName, String slotName) {
super(tableName, slotName);
}
public OffsetBuilder(String tableName) {
super(tableName);
}
/**
* 设定每个shardId的offset.
*
* @param shardId
* @param offset
* @return
*/
public OffsetBuilder addShardStartOffset(int shardId, BinlogOffset offset) {
if (offsetMap == null) {
offsetMap = new HashMap<>();
}
offsetMap.putIfAbsent(shardId, offset);
return this;
}
/**
* 为一组shard设置offset.
* 一般用于批量设置启动时间.
*
* @param shardIds
* @param offset
* @return
*/
public OffsetBuilder addShardsStartOffset(Set shardIds, BinlogOffset offset) {
shardIds.forEach(shardId -> addShardStartOffset(shardId, offset));
return this;
}
public OffsetBuilder addShardStartOffsetForPartition(String partitionName, int shardId, BinlogOffset offset) {
if (partitionToBuilderMap == null) {
partitionToBuilderMap = new HashMap<>();
}
OffsetBuilder partitionBuilder = partitionToBuilderMap.computeIfAbsent(partitionName, k -> new OffsetBuilder(partitionName));
partitionBuilder.addShardStartOffset(shardId, offset);
return this;
}
public OffsetBuilder addShardsStartOffsetForPartition(String partitionName, Set shardIds, BinlogOffset offset) {
if (partitionToBuilderMap == null) {
partitionToBuilderMap = new HashMap<>();
}
OffsetBuilder partitionBuilder = partitionToBuilderMap.computeIfAbsent(partitionName, k -> new OffsetBuilder(partitionName));
partitionBuilder.addShardsStartOffset(shardIds, offset);
return this;
}
public OffsetBuilder addPartitionValuesToSubscribe(String[] partitionValues) {
partitionValuesToSubscribe.addAll(Arrays.asList(partitionValues));
return this;
}
// Since logical partition table supports multiple partition columns, we need to pass in
// a 2D array.
public OffsetBuilder addLogicalPartitionValuesToSubscribe(String[][] logicalPartitionValues) {
logicalPartitionValuesToSubscribe = logicalPartitionValues;
return this;
}
public OffsetBuilder addLogicalPartitionNamesToSubscribe(String[] logicalPartitionNames) {
logicalPartitionNamesToSubscribe = logicalPartitionNames;
return this;
}
public Subscribe build() {
if (offsetMap == null) {
throw new InvalidParameterException("must call addShardStartOffset before build");
}
NavigableMap partitionToSubscribeMap = new TreeMap<>();
if (partitionToBuilderMap != null) {
partitionToBuilderMap.forEach((partition, subscribe) -> partitionToSubscribeMap.put(partition, subscribe.build()));
}
if (!partitionValuesToSubscribe.isEmpty()) {
// Initialize Subscribe for physical partition table.
return new Subscribe(tableName, slotName, offsetMap, null, partitionToSubscribeMap, partitionValuesToSubscribe.toArray(new String[0]));
} else {
// Initialize Subscribe for logical partition table.
return new Subscribe(tableName, slotName, offsetMap, null, partitionToSubscribeMap, logicalPartitionNamesToSubscribe, logicalPartitionValuesToSubscribe);
}
}
}
/**
* 指定时间时用的, 不能指定shard, 运行时会默认给表的所有shard指定相同的启动时间.
*/
public static class StartTimeBuilder extends Builder {
private String binlogReadStartTime;
private List partitionValuesToSubscribe = new ArrayList<>();
private String[] logicalPartitionNamesToSubscribe;
private String[][] logicalPartitionValuesToSubscribe;
public StartTimeBuilder(String tableName, String slotName) {
super(tableName, slotName);
}
public StartTimeBuilder(String tableName) {
super(tableName);
}
public StartTimeBuilder setBinlogReadStartTime(String binlogReadStartTime) {
this.binlogReadStartTime = binlogReadStartTime;
return this;
}
public StartTimeBuilder addPartitionValuesToSubscribe(String[] partitionValues) {
partitionValuesToSubscribe.addAll(Arrays.asList(partitionValues));
return this;
}
// Since logical partition table supports multiple partition columns, we need to pass in
// a 2D array.
public StartTimeBuilder addLogicalPartitionValuesToSubscribe(String[][] logicalPartitionValues) {
logicalPartitionValuesToSubscribe = logicalPartitionValues;
return this;
}
public StartTimeBuilder addLogicalPartitionNamesToSubscribe(String[] logicalPartitionNames) {
logicalPartitionNamesToSubscribe = logicalPartitionNames;
return this;
}
public Subscribe build() {
if (!partitionValuesToSubscribe.isEmpty()) {
// Initialize Subscribe for physical partition table.
return new Subscribe(tableName, slotName, null, binlogReadStartTime, new TreeMap<>(), partitionValuesToSubscribe.toArray(new String[0]));
} else {
// Initialize Subscribe for logical partition table.
return new Subscribe(tableName, slotName, null, binlogReadStartTime, new TreeMap<>(), logicalPartitionNamesToSubscribe, logicalPartitionValuesToSubscribe);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy