diff --git a/src/main/java/com/actiontech/dble/backend/datasource/LocalReadLoadBalancer.java b/src/main/java/com/actiontech/dble/backend/datasource/LocalReadLoadBalancer.java new file mode 100644 index 000000000..7cc435a23 --- /dev/null +++ b/src/main/java/com/actiontech/dble/backend/datasource/LocalReadLoadBalancer.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016-2022 ActionTech. + * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher. + */ + +package com.actiontech.dble.backend.datasource; + +import com.actiontech.dble.config.model.SystemConfig; +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import org.apache.commons.lang.StringUtils; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; + +public class LocalReadLoadBalancer extends AbstractLoadBalancer { + + private final ThreadLocalRandom random = ThreadLocalRandom.current(); + + public LocalReadLoadBalancer() { + } + + @Override + protected PhysicalDbInstance doSelect(List okSources) { + List matchSources = matchSources(okSources); + if (matchSources.isEmpty()) { + matchSources = okSources; + } + int length = matchSources.size(); + int totalWeight = 0; + boolean sameWeight = true; + for (int i = 0; i < length; i++) { + int readWeight = matchSources.get(i).getConfig().getReadWeight(); + totalWeight += readWeight; + if (sameWeight && i > 0 && readWeight != matchSources.get(i - 1).getConfig().getReadWeight()) { + sameWeight = false; + } + } + + if (totalWeight > 0 && !sameWeight) { + // random by different weight + int offset = random.nextInt(totalWeight); + for (PhysicalDbInstance okSource : matchSources) { + offset -= okSource.getConfig().getReadWeight(); + if (offset < 0) { + return okSource; + } + } + } + return matchSources.get(random.nextInt(length)); + } + + private List matchSources(List okSources) { + String district = SystemConfig.getInstance().getDistrict(); + String dataCenter = SystemConfig.getInstance().getDataCenter(); + if (Strings.isNullOrEmpty(district)) { + return okSources; + } + List firstSources = Lists.newArrayList(); + List secondSources = Lists.newArrayList(); + List otherSources; + + otherSources = okSources.stream().filter(okSource -> okSource.isAlive()).collect(Collectors.toList()); + + for (PhysicalDbInstance okSource : otherSources) { + String dbDistrict = okSource.getConfig().getDbDistrict(); + String dbDataCenter = okSource.getConfig().getDbDataCenter(); + if (StringUtils.equals(district, dbDistrict)) { + secondSources.add(okSource); + if (StringUtils.equals(dataCenter, dbDataCenter)) { + firstSources.add(okSource); + } + } + } + if (!firstSources.isEmpty()) { + return firstSources; + } + if (!secondSources.isEmpty()) { + return secondSources; + } + return otherSources; + + } +} diff --git a/src/main/java/com/actiontech/dble/backend/datasource/PhysicalDbGroup.java b/src/main/java/com/actiontech/dble/backend/datasource/PhysicalDbGroup.java index 48a681ec8..9d08ce465 100644 --- a/src/main/java/com/actiontech/dble/backend/datasource/PhysicalDbGroup.java +++ b/src/main/java/com/actiontech/dble/backend/datasource/PhysicalDbGroup.java @@ -58,6 +58,7 @@ public class PhysicalDbGroup { private final int rwSplitMode; protected String[] schemas; private final LoadBalancer loadBalancer = new RandomLoadBalancer(); + private final LocalReadLoadBalancer localReadLoadBalancer = new LocalReadLoadBalancer(); private final ReentrantReadWriteLock adjustLock = new ReentrantReadWriteLock(); private boolean shardingUseless = true; @@ -293,15 +294,28 @@ public class PhysicalDbGroup { * rwsplit user * * @param master - * @param write + * @param writeStatistical * @return * @throws IOException */ - public PhysicalDbInstance rwSelect(Boolean master, Boolean write) throws IOException { - if (Objects.nonNull(write)) { - return select(master, false, write); + public PhysicalDbInstance rwSelect(Boolean master, Boolean writeStatistical) throws IOException { + return rwSelect(master, writeStatistical, false); + } + + /** + * rwsplit user + * + * @param master + * @param writeStatistical + * @param localRead only the SELECT and show statements attempt to localRead + * @return + * @throws IOException + */ + public PhysicalDbInstance rwSelect(Boolean master, Boolean writeStatistical, boolean localRead) throws IOException { + if (Objects.nonNull(writeStatistical)) { + return select(master, false, writeStatistical, localRead); } - return select(master, false, Objects.nonNull(master) ? master : false); + return select(master, false, Objects.nonNull(master) ? master : false, localRead); } /** @@ -319,7 +333,22 @@ public class PhysicalDbGroup { return select(master, isForUpdate, false); } - public PhysicalDbInstance select(Boolean master, boolean isForUpdate, boolean write) throws IOException { + public PhysicalDbInstance select(Boolean master, boolean isForUpdate, boolean writeStatistical) throws IOException { + return select(master, isForUpdate, writeStatistical, false); + } + + /** + * Select an instance + * + * @param master + * @param isForUpdate + * @param writeStatistical + * @param localRead only the SELECT and show statements attempt to localRead + * @return + * @throws IOException + */ + public PhysicalDbInstance select(Boolean master, boolean isForUpdate, boolean writeStatistical, boolean localRead) throws IOException { + if (rwSplitMode == RW_SPLIT_OFF && (master != null && !master)) { LOGGER.warn("force slave,but the dbGroup[{}] doesn't contains active slave dbInstance", groupName); throw new IOException("force slave,but the dbGroup[" + groupName + "] doesn't contain active slave dbInstance"); @@ -330,7 +359,7 @@ public class PhysicalDbGroup { if (LOGGER.isDebugEnabled()) { LOGGER.debug("select write {}", writeDbInstance); } - if (write) { + if (writeStatistical) { writeDbInstance.incrementWriteCount(); } else { writeDbInstance.incrementReadCount(); @@ -345,6 +374,20 @@ public class PhysicalDbGroup { if (instances.size() == 0) { throw new IOException("the dbGroup[" + groupName + "] doesn't contain active dbInstance."); } + + if (localRead) { + PhysicalDbInstance selectInstance = localReadLoadBalancer.select(instances); + selectInstance.incrementReadCount(); + if (selectInstance.isAlive()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("select {}", selectInstance); + } + return selectInstance; + } else { + reportError(selectInstance); + return selectInstance; + } + } PhysicalDbInstance selectInstance = loadBalancer.select(instances); selectInstance.incrementReadCount(); if (selectInstance.isAlive()) { diff --git a/src/main/java/com/actiontech/dble/cluster/zkprocess/entity/dbGroups/DBInstance.java b/src/main/java/com/actiontech/dble/cluster/zkprocess/entity/dbGroups/DBInstance.java index 4c968ac9c..e33e9b15f 100644 --- a/src/main/java/com/actiontech/dble/cluster/zkprocess/entity/dbGroups/DBInstance.java +++ b/src/main/java/com/actiontech/dble/cluster/zkprocess/entity/dbGroups/DBInstance.java @@ -7,6 +7,7 @@ package com.actiontech.dble.cluster.zkprocess.entity.dbGroups; import com.actiontech.dble.cluster.zkprocess.entity.Propertied; import com.actiontech.dble.cluster.zkprocess.entity.Property; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; @@ -54,6 +55,12 @@ public class DBInstance implements Propertied { @XmlAttribute protected String databaseType; + @XmlAttribute + protected String dbDistrict; + + @XmlAttribute + protected String dbDataCenter; + protected List property; protected transient String dbGroup; @@ -62,7 +69,7 @@ public class DBInstance implements Propertied { } public DBInstance(String name, String url, String password, String user, Integer maxCon, Integer minCon, String disabled, String id, String readWeight, - Boolean primary, List property, String usingDecrypt, String databaseType) { + Boolean primary, List property, String usingDecrypt, String databaseType, String dbDistrict, String dbDataCenter) { this.name = name; this.url = url; this.password = password; @@ -76,6 +83,8 @@ public class DBInstance implements Propertied { this.property = property; this.usingDecrypt = usingDecrypt; this.databaseType = databaseType; + this.dbDistrict = dbDistrict; + this.dbDataCenter = dbDataCenter; } @Override @@ -202,6 +211,23 @@ public class DBInstance implements Propertied { this.databaseType = databaseType; } + public String getDbDistrict() { + return dbDistrict; + } + + public void setDbDistrict(String dbDistrict) { + this.dbDistrict = dbDistrict; + } + + public String getDbDataCenter() { + return dbDataCenter; + } + + public void setDbDataCenter(String dbDataCenter) { + this.dbDataCenter = dbDataCenter; + } + + @Override public String toString() { return "dbInstance [name=" + @@ -226,6 +252,10 @@ public class DBInstance implements Propertied { readWeight + ", databaseType=" + databaseType + + ", dbDistrict=" + + dbDistrict + + ", dbDataCenter=" + + dbDataCenter + ",property=" + property + "]"; diff --git a/src/main/java/com/actiontech/dble/config/converter/DBConverter.java b/src/main/java/com/actiontech/dble/config/converter/DBConverter.java index e346d819d..d71ed7f08 100644 --- a/src/main/java/com/actiontech/dble/config/converter/DBConverter.java +++ b/src/main/java/com/actiontech/dble/config/converter/DBConverter.java @@ -30,6 +30,7 @@ import com.actiontech.dble.config.util.ParameterMapping; import com.actiontech.dble.util.DecryptUtil; import com.actiontech.dble.util.LongUtil; import com.actiontech.dble.util.StringUtil; +import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.gson.Gson; @@ -37,6 +38,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; +import java.nio.charset.Charset; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -255,6 +257,13 @@ public class DBConverter { conf.setMaxCon(maxCon); conf.setMinCon(minCon); conf.setReadWeight(readWeight); + + String dbDistrict = dbInstance.getDbDistrict(); + checkChineseAndRules(dbDistrict, "dbDistrict"); + String dbDataCenter = dbInstance.getDbDataCenter(); + checkChineseAndRules(dbDataCenter, "dbDataCenter"); + conf.setDbDistrict(dbDistrict); + conf.setDbDataCenter(dbDataCenter); // id String id = dbInstance.getId(); if (StringUtil.isEmpty(id)) { @@ -280,6 +289,18 @@ public class DBConverter { return dataBaseType; } + private void checkChineseAndRules(String val, String name) { + if (Objects.nonNull(val)) { + String chinese = val.replaceAll(PATTERN_DB.toString(), ""); + if (Strings.isNullOrEmpty(chinese)) { + return; + } + if (!StringUtil.isChinese(chinese)) { + throw new ConfigException("properties of system may not recognized:" + val + "the " + Charset.defaultCharset().name() + " encoding is recommended, dbInstance name " + name + " show be use u4E00-u9FA5a-zA-Z_0-9\\-\\."); + } + } + } + private void checkProperty(List errorMsgList, Property property) { String value = property.getValue(); if (StringUtil.isBlank(value)) { diff --git a/src/main/java/com/actiontech/dble/config/model/SystemConfig.java b/src/main/java/com/actiontech/dble/config/model/SystemConfig.java index 3ef3c06d9..df90a1759 100644 --- a/src/main/java/com/actiontech/dble/config/model/SystemConfig.java +++ b/src/main/java/com/actiontech/dble/config/model/SystemConfig.java @@ -8,13 +8,19 @@ package com.actiontech.dble.config.model; import com.actiontech.dble.backend.mysql.CharsetUtil; import com.actiontech.dble.config.Isolations; import com.actiontech.dble.config.ProblemReporter; +import com.actiontech.dble.config.converter.DBConverter; import com.actiontech.dble.config.util.ParameterMapping; import com.actiontech.dble.config.util.StartProblemReporter; import com.actiontech.dble.memory.unsafe.Platform; import com.actiontech.dble.util.NetUtil; +import com.actiontech.dble.util.StringUtil; +import com.google.common.base.Strings; import java.io.File; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.Objects; import static com.actiontech.dble.config.model.db.PoolConfig.DEFAULT_IDLE_TIMEOUT; @@ -209,6 +215,9 @@ public final class SystemConfig { // For rwSplitUser, Implement stickiness for read and write instances, the default value is 1000ms private long rwStickyTime = 1000; + private String district = null; + private String dataCenter = null; + private boolean closeHeartBeatRecord = false; @@ -1517,6 +1526,25 @@ public final class SystemConfig { routePenetrationRules = sqlPenetrationRegexesTmp; } + public String getDistrict() { + return district; + } + + @SuppressWarnings("unused") + public void setDistrict(String district) throws UnsupportedEncodingException { + checkChineseProperty(district, "district"); + this.district = district; + } + + public String getDataCenter() { + return dataCenter; + } + + @SuppressWarnings("unused") + public void setDataCenter(String dataCenter) { + checkChineseProperty(dataCenter, "dataCenter"); + this.dataCenter = dataCenter; + } @Override public String toString() { @@ -1618,6 +1646,8 @@ public final class SystemConfig { ", closeHeartBeatRecord=" + closeHeartBeatRecord + ", enableRoutePenetration=" + enableRoutePenetration + ", routePenetrationRules='" + routePenetrationRules + '\'' + + ", district='" + district + + ", dataCenter='" + dataCenter + "]"; } @@ -1628,4 +1658,21 @@ public final class SystemConfig { public void setCloseHeartBeatRecord(boolean closeHeartBeatRecord) { this.closeHeartBeatRecord = closeHeartBeatRecord; } + + private void checkChineseProperty(String val, String name) { + if (Objects.nonNull(val)) { + int length = 11; + if (val.length() > length) { + problemReporter.warn("Property [ " + name + " ] " + val + " in bootstrap.cnf is illegal,the value contains a maximum of " + length + " characters"); + } + + String chinese = val.replaceAll(DBConverter.PATTERN_DB.toString(), ""); + if (Strings.isNullOrEmpty(chinese)) { + return; + } + if (!StringUtil.isChinese(chinese)) { + problemReporter.warn("Property [ " + name + " ] " + val + " in bootstrap.cnf is illegal,the " + Charset.defaultCharset().name() + " encoding is recommended, Property [ " + name + " ] show be use u4E00-u9FA5a-zA-Z_0-9\\-\\."); + } + } + } } diff --git a/src/main/java/com/actiontech/dble/config/model/db/DbInstanceConfig.java b/src/main/java/com/actiontech/dble/config/model/db/DbInstanceConfig.java index 9f0d1f425..089518484 100644 --- a/src/main/java/com/actiontech/dble/config/model/db/DbInstanceConfig.java +++ b/src/main/java/com/actiontech/dble/config/model/db/DbInstanceConfig.java @@ -24,6 +24,8 @@ public class DbInstanceConfig { private volatile PoolConfig poolConfig; private final boolean usingDecrypt; private DataBaseType dataBaseType; + private String dbDistrict; + private String dbDataCenter; public DbInstanceConfig(String instanceName, String ip, int port, String url, String user, String password, boolean disabled, boolean primary, boolean usingDecrypt, DataBaseType dataBaseType) { @@ -149,6 +151,21 @@ public class DbInstanceConfig { return false; } + public String getDbDistrict() { + return dbDistrict; + } + + public void setDbDistrict(String dbDistrict) { + this.dbDistrict = dbDistrict; + } + + public String getDbDataCenter() { + return dbDataCenter; + } + + public void setDbDataCenter(String dbDataCenter) { + this.dbDataCenter = dbDataCenter; + } @Override public String toString() { diff --git a/src/main/java/com/actiontech/dble/rwsplit/RWSplitNonBlockingSession.java b/src/main/java/com/actiontech/dble/rwsplit/RWSplitNonBlockingSession.java index 16f64c047..5cb7e7bcf 100644 --- a/src/main/java/com/actiontech/dble/rwsplit/RWSplitNonBlockingSession.java +++ b/src/main/java/com/actiontech/dble/rwsplit/RWSplitNonBlockingSession.java @@ -107,31 +107,39 @@ public class RWSplitNonBlockingSession extends Session { execute(master, null, callback); } - public void execute(Boolean master, Callback callback, boolean write) { - execute(master, null, callback, write); + public void execute(Boolean master, Callback callback, boolean writeStatistical) { + execute(master, null, callback, writeStatistical, false); + } + + /** + * @param master + * @param callback + * @param writeStatistical + * @param localRead only the SELECT and show statements attempt to localRead + */ + public void execute(Boolean master, Callback callback, boolean writeStatistical, boolean localRead) { + execute(master, null, callback, writeStatistical, localRead && !rwGroup.isRwSplitUseless()); } public void execute(Boolean master, byte[] originPacket, Callback callback) { + execute(master, originPacket, callback, false, false); + } + + public void execute(Boolean master, byte[] originPacket, Callback callback, boolean writeStatistical) { + execute(master, originPacket, callback, writeStatistical, false); + } + + public void execute(Boolean master, byte[] originPacket, Callback callback, boolean writeStatistical, boolean localRead) { try { RWSplitHandler handler = getRwSplitHandler(originPacket, callback); if (handler == null) return; - getConnection(handler, master, null); + getConnection(handler, master, isWriteStatistical(writeStatistical), localRead); } catch (SQLSyntaxErrorException | IOException se) { rwSplitService.writeErrMessage(ErrorCode.ER_UNKNOWN_ERROR, se.getMessage()); } } - public void execute(Boolean master, byte[] originPacket, Callback callback, boolean write) { - try { - RWSplitHandler handler = getRwSplitHandler(originPacket, callback); - if (handler == null) return; - getConnection(handler, master, isWrite(write)); - } catch (SQLSyntaxErrorException | IOException se) { - rwSplitService.writeErrMessage(ErrorCode.ER_UNKNOWN_ERROR, se.getMessage()); - } - } - - public void getConnection(RWSplitHandler handler, Boolean master, Boolean write) { + public void getConnection(RWSplitHandler handler, Boolean master, Boolean writeStatistical, boolean localRead) { try { Boolean isMaster = canRunOnMaster(master); // first boolean firstValue = isMaster == null ? false : isMaster; @@ -146,7 +154,7 @@ public class RWSplitNonBlockingSession extends Session { resetLastSqlResponseTime(); } } - PhysicalDbInstance instance = reSelectRWDbGroup(rwGroup).rwSelect(isMaster, write); // second + PhysicalDbInstance instance = reSelectRWDbGroup(rwGroup).rwSelect(isMaster, writeStatistical, localRead); // second boolean isWrite = !instance.isReadInstance(); this.setPreSendIsWrite(isWrite && firstValue); // ensure that the first and second results are write instances checkDest(isWrite); @@ -189,11 +197,11 @@ public class RWSplitNonBlockingSession extends Session { return handler; } - private boolean isWrite(boolean write) { + private boolean isWriteStatistical(boolean writeStatistical) { if (!rwSplitService.isAutocommit() || rwSplitService.isTxStart() || rwSplitService.isUsingTmpTable()) { return true; } - return write; + return writeStatistical; } private Boolean canRunOnMaster(Boolean master) { diff --git a/src/main/java/com/actiontech/dble/services/manager/information/tables/DbleDbInstance.java b/src/main/java/com/actiontech/dble/services/manager/information/tables/DbleDbInstance.java index 5be04795d..4000e9f97 100644 --- a/src/main/java/com/actiontech/dble/services/manager/information/tables/DbleDbInstance.java +++ b/src/main/java/com/actiontech/dble/services/manager/information/tables/DbleDbInstance.java @@ -73,6 +73,10 @@ public class DbleDbInstance extends ManagerWritableTable { private static final String COLUMN_DATABASE_TYPE = "database_type"; + private static final String COLUMN_DB_DISTRICT = "db_district"; + + private static final String COLUMN_DB_DATA_CENTER = "db_data_center"; + private static final String COLUMN_LAST_HEARTBEAT_ACK_TIMESTAMP = "last_heartbeat_ack_timestamp"; private static final String COLUMN_LAST_HEARTBEAT_ACK = "last_heartbeat_ack"; @@ -114,7 +118,7 @@ public class DbleDbInstance extends ManagerWritableTable { private static final String COLUMN_FLOW_LOW_LEVEL = "flow_low_level"; public DbleDbInstance() { - super(TABLE_NAME, 34); + super(TABLE_NAME, 36); setNotWritableColumnSet(COLUMN_ACTIVE_CONN_COUNT, COLUMN_IDLE_CONN_COUNT, COLUMN_READ_CONN_REQUEST, COLUMN_WRITE_CONN_REQUEST, COLUMN_LAST_HEARTBEAT_ACK_TIMESTAMP, COLUMN_LAST_HEARTBEAT_ACK, COLUMN_HEARTBEAT_STATUS, COLUMN_HEARTBEAT_FAILURE_IN_LAST_5MIN); @@ -168,6 +172,12 @@ public class DbleDbInstance extends ManagerWritableTable { columns.put(COLUMN_DATABASE_TYPE, new ColumnMeta(COLUMN_DATABASE_TYPE, "varchar(11)", true, "mysql")); columnsType.put(COLUMN_DATABASE_TYPE, Fields.FIELD_TYPE_VAR_STRING); + columns.put(COLUMN_DB_DISTRICT, new ColumnMeta(COLUMN_DB_DISTRICT, "varchar(11)", true, null)); + columnsType.put(COLUMN_DB_DISTRICT, Fields.FIELD_TYPE_VAR_STRING); + + columns.put(COLUMN_DB_DATA_CENTER, new ColumnMeta(COLUMN_DB_DATA_CENTER, "varchar(11)", true, null)); + columnsType.put(COLUMN_DB_DATA_CENTER, Fields.FIELD_TYPE_VAR_STRING); + columns.put(COLUMN_LAST_HEARTBEAT_ACK_TIMESTAMP, new ColumnMeta(COLUMN_LAST_HEARTBEAT_ACK_TIMESTAMP, "varchar(64)", true)); columnsType.put(COLUMN_LAST_HEARTBEAT_ACK_TIMESTAMP, Fields.FIELD_TYPE_VAR_STRING); @@ -255,6 +265,8 @@ public class DbleDbInstance extends ManagerWritableTable { map.put(COLUMN_WRITE_CONN_REQUEST, String.valueOf(dbInstance.getCount(false))); map.put(COLUMN_DISABLED, String.valueOf(dbInstance.isDisabled())); map.put(COLUMN_DATABASE_TYPE, String.valueOf(dbInstanceConfig.getDataBaseType()).toLowerCase()); + map.put(COLUMN_DB_DISTRICT, Optional.ofNullable(dbInstanceConfig.getDbDistrict()).orElse("").toLowerCase()); + map.put(COLUMN_DB_DATA_CENTER, Optional.ofNullable(dbInstanceConfig.getDbDataCenter()).orElse("").toLowerCase()); map.put(COLUMN_LAST_HEARTBEAT_ACK_TIMESTAMP, heartbeat.getLastActiveTime()); map.put(COLUMN_LAST_HEARTBEAT_ACK, heartbeat.getStatusStr()); map.put(COLUMN_HEARTBEAT_STATUS, heartbeat.isChecking() ? MySQLHeartbeat.CHECK_STATUS_CHECKING : MySQLHeartbeat.CHECK_STATUS_IDLE); @@ -415,6 +427,12 @@ public class DbleDbInstance extends ManagerWritableTable { case COLUMN_DATABASE_TYPE: dbInstance.setDatabaseType(entry.getValue()); break; + case COLUMN_DB_DISTRICT: + dbInstance.setDbDistrict(entry.getValue()); + break; + case COLUMN_DB_DATA_CENTER: + dbInstance.setDbDataCenter(entry.getValue()); + break; case COLUMN_MIN_CONN_COUNT: if (!StringUtil.isBlank(entry.getValue())) { dbInstance.setMinCon(IntegerUtil.parseInt(entry.getValue())); diff --git a/src/main/java/com/actiontech/dble/services/rwsplit/RWSplitQueryHandler.java b/src/main/java/com/actiontech/dble/services/rwsplit/RWSplitQueryHandler.java index 569601904..e3292e681 100644 --- a/src/main/java/com/actiontech/dble/services/rwsplit/RWSplitQueryHandler.java +++ b/src/main/java/com/actiontech/dble/services/rwsplit/RWSplitQueryHandler.java @@ -70,7 +70,7 @@ public class RWSplitQueryHandler implements FrontendQueryHandler { session.execute(true, (isSuccess, resp, rwSplitService) -> rwSplitService.setSchema(schema)); break; case RwSplitServerParse.SHOW: - session.execute(true, null, false); + session.execute(true, null, false, true); break; case RwSplitServerParse.SELECT: RwSplitSelectHandler.handle(sql, session.getService(), rs >>> 8); diff --git a/src/main/java/com/actiontech/dble/services/rwsplit/handle/RwSplitSelectHandler.java b/src/main/java/com/actiontech/dble/services/rwsplit/handle/RwSplitSelectHandler.java index bb8d304c7..06ee3cc90 100644 --- a/src/main/java/com/actiontech/dble/services/rwsplit/handle/RwSplitSelectHandler.java +++ b/src/main/java/com/actiontech/dble/services/rwsplit/handle/RwSplitSelectHandler.java @@ -26,10 +26,10 @@ public final class RwSplitSelectHandler { int rs2 = RwSplitServerParseSelect.parseSpecial(stmt); switch (rs2) { case RwSplitServerParseSelect.LOCK_READ: - service.getSession2().execute(true, null, false); + service.getSession2().execute(true, null, false, true); break; default: - service.getSession2().execute(null, null, false); + service.getSession2().execute(null, null, false, true); break; } break; diff --git a/src/main/java/com/actiontech/dble/singleton/SystemParams.java b/src/main/java/com/actiontech/dble/singleton/SystemParams.java index 5e48695f3..e5698df82 100644 --- a/src/main/java/com/actiontech/dble/singleton/SystemParams.java +++ b/src/main/java/com/actiontech/dble/singleton/SystemParams.java @@ -139,6 +139,8 @@ public final class SystemParams { readOnlyParams.add(new ParamInfo("closeHeartBeatRecord", sysConfig.isCloseHeartBeatRecord() + "", "close heartbeat record. if closed, `show @@dbinstance.synstatus`,`show @@dbinstance.syndetail`,`show @@heartbeat.detail` will be empty and `show @@heartbeat`'s EXECUTE_TIME will be '-' .The default value is false")); readOnlyParams.add(new ParamInfo("enableRoutePenetration", sysConfig.isEnableRoutePenetration() + "", "Whether enable route penetration.The default value is 0")); readOnlyParams.add(new ParamInfo("routePenetrationRules", sysConfig.getRoutePenetrationRules() + "", "The config of route penetration.The default value is ''")); + readOnlyParams.add(new ParamInfo("district", sysConfig.getDistrict() + "", "The location of the DBLE")); + readOnlyParams.add(new ParamInfo("dataCenter", sysConfig.getDataCenter() + "", "The data center where the DBLE resides")); } diff --git a/src/main/java/com/actiontech/dble/util/StringUtil.java b/src/main/java/com/actiontech/dble/util/StringUtil.java index 8b9230942..f1c58bf2c 100644 --- a/src/main/java/com/actiontech/dble/util/StringUtil.java +++ b/src/main/java/com/actiontech/dble/util/StringUtil.java @@ -372,6 +372,7 @@ public final class StringUtil { /** * option to ignore case depending on the condition + * * @param str1 * @param str2 * @param ignoreCase @@ -609,4 +610,18 @@ public final class StringUtil { } return orgStr; } + + /** + * src: https://stackoverflow.com/questions/26357938/detect-chinese-character-in-java/26357985 + *

+ * Now Character.isIdeographic(int codepoint) would tell wether the codepoint is a C (Chinese) ideograph. + * Nearer is using Character.UnicodeScript.HAN. + * + * @param val + * @return + */ + public static boolean isChinese(String val) { + return val.codePoints().allMatch(codepoint -> Character.UnicodeScript.of(codepoint) == Character.UnicodeScript.HAN); + } + } diff --git a/src/main/resources/db_detail.xsd b/src/main/resources/db_detail.xsd index aad92fa3f..7f2b92828 100644 --- a/src/main/resources/db_detail.xsd +++ b/src/main/resources/db_detail.xsd @@ -44,6 +44,8 @@ + +