Merge pull request #3767 from actiontech/fix/test-2010

fix[inner-2290]:merge dble_information related pr
This commit is contained in:
LUA
2023-07-13 13:17:53 +08:00
committed by GitHub
18 changed files with 615 additions and 419 deletions
@@ -18,6 +18,7 @@ public class Property implements Named {
@XmlValue
protected String value;
@XmlAttribute(name = "name")
protected String name;
@@ -20,14 +20,18 @@ public class DBGroup implements Named {
@XmlAttribute(required = true)
protected Integer rwSplitMode;
@XmlAttribute(required = true)
protected String name;
@XmlAttribute
protected Integer delayThreshold;
@XmlAttribute
protected String disableHA;
protected HeartBeat heartbeat;
protected List<DBInstance> dbInstance;
public DBGroup() {
@@ -21,22 +21,31 @@ public class DBInstance implements Propertied {
@XmlAttribute(required = true)
protected String name;
@XmlAttribute(required = true)
protected String url;
@XmlAttribute(required = true)
protected String password;
@XmlAttribute(required = true)
protected String user;
@XmlAttribute(required = true)
protected Integer maxCon;
@XmlAttribute(required = true)
protected Integer minCon;
@XmlAttribute
protected String usingDecrypt;
@XmlAttribute
protected String disabled;
@XmlAttribute
protected String id;
@XmlAttribute
protected String readWeight;
@@ -45,6 +54,8 @@ public class DBInstance implements Propertied {
protected List<Property> property;
protected transient String dbGroup;
public DBInstance() {
}
@@ -172,6 +183,13 @@ public class DBInstance implements Propertied {
this.property = property;
}
public void setDbGroup(String dbGroup) {
this.dbGroup = dbGroup;
}
public String getDbGroup() {
return dbGroup;
}
@Override
public String toString() {
return "dbInstance [name=" +
@@ -5,6 +5,7 @@
package com.actiontech.dble.cluster.zkprocess.entity.dbGroups;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
@@ -12,8 +13,10 @@ import javax.xml.bind.annotation.*;
public class HeartBeat {
@XmlValue
protected String value;
@XmlAttribute
protected Integer timeout;
@XmlAttribute
protected Integer errorRetryCount;
@@ -46,6 +49,11 @@ public class HeartBeat {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "heartbeat [timeout=" +
@@ -36,11 +36,11 @@ public class UserConfig {
this.isEncrypt = isEncrypt;
this.whiteIPs = genWhiteIPs(strWhiteIPs);
int maxConn = -1;
int maxConn = 0;
if (!StringUtil.isEmpty(strMaxCon)) {
maxConn = Integer.parseInt(strMaxCon);
if (maxConn < 0) {
maxConn = -1;
maxConn = 0;
}
}
this.maxCon = maxConn;
@@ -88,12 +88,14 @@ public final class DeleteHandler {
return;
}
ManagerWritableTable managerTable = (ManagerWritableTable) managerBaseTable;
int rowSize;
int rowSize = 0;
boolean lockFlag = managerTable.getLock().tryLock();
if (!lockFlag) {
service.writeErrMessage(ErrorCode.ER_YES, "Other threads are executing management commands(insert/update/delete), please try again later.");
return;
}
boolean isSuccess = true;
String errorMsg = null;
try {
List<RowDataPacket> foundRows = ManagerTableUtil.getFoundRows(service, managerTable, delete.getWhere());
Set<LinkedHashMap<String, String>> affectPks = ManagerTableUtil.getAffectPks(service, managerTable, foundRows, null);
@@ -102,37 +104,45 @@ public final class DeleteHandler {
ReloadConfig.execute(service, 0, false, new ConfStatus(ConfStatus.Status.MANAGER_DELETE, managerTable.getTableName()));
}
} catch (SQLException e) {
service.writeErrMessage(e.getSQLState(), e.getMessage(), e.getErrorCode());
return;
isSuccess = false;
errorMsg = e.getMessage();
} catch (ConfigException e) {
service.writeErrMessage(ErrorCode.ER_YES, "Delete failure.The reason is " + e.getMessage());
return;
isSuccess = false;
errorMsg = "Delete failure.The reason is " + e.getMessage();
} catch (Exception e) {
isSuccess = false;
if (e.getCause() instanceof ConfigException) {
//reload fail
errorMsg = "Delete failure.The reason is " + e.getMessage();
LOGGER.warn("Delete failure.The reason is " + e);
handleConfigException(e, service, managerTable);
} else {
service.writeErrMessage(ErrorCode.ER_YES, "unknown error:" + e.getMessage());
errorMsg = "unknown error:" + e.getMessage();
LOGGER.warn("unknown error:", e);
}
return;
} finally {
managerTable.deleteBackupFile();
managerTable.getLock().unlock();
}
OkPacket ok = new OkPacket();
ok.setPacketId(1);
ok.setAffectedRows(rowSize);
ok.write(service.getConnection());
writePacket(isSuccess, rowSize, service, errorMsg);
}
private void writePacket(boolean isSuccess, int rowSize, ManagerService service, String errorMsg) {
if (isSuccess) {
OkPacket ok = new OkPacket();
ok.setPacketId(1);
ok.setAffectedRows(rowSize);
ok.write(service.getConnection());
} else {
service.writeErrMessage(ErrorCode.ER_YES, errorMsg);
}
}
private void handleConfigException(Exception e, ManagerService service, ManagerWritableTable managerTable) {
try {
managerTable.rollbackXmlFile();
} catch (IOException ioException) {
service.writeErrMessage(ErrorCode.ER_YES, "unknown error:" + e.getMessage());
return;
LOGGER.warn("unknown error:", e);
}
service.writeErrMessage(ErrorCode.ER_YES, "Delete failure.The reason is " + e.getMessage());
}
}
@@ -59,7 +59,9 @@ public final class InsertHandler {
service.writeErrMessage(ErrorCode.ER_YES, "Other threads are executing management commands(insert/update/delete), please try again later.");
return;
}
int rowSize;
int rowSize = 0;
boolean isSuccess = true;
String errorMsg = null;
try {
rows = managerTable.makeInsertRows(columns, insert.getValuesList());
managerTable.checkPrimaryKeyDuplicate(rows);
@@ -67,26 +69,33 @@ public final class InsertHandler {
if (rowSize != 0) {
ReloadConfig.execute(service, 0, false, new ConfStatus(ConfStatus.Status.MANAGER_INSERT, managerTable.getTableName()));
}
managerTable.afterExecute();
} catch (SQLException e) {
service.writeErrMessage(StringUtil.isEmpty(e.getSQLState()) ? "HY000" : e.getSQLState(), e.getMessage(), e.getErrorCode());
return;
isSuccess = false;
errorMsg = e.getMessage();
} catch (ConfigException e) {
service.writeErrMessage(ErrorCode.ER_YES, "Insert failure.The reason is " + e.getMessage());
return;
isSuccess = false;
errorMsg = "Insert failure.The reason is " + e.getMessage();
} catch (Exception e) {
isSuccess = false;
if (e.getCause() instanceof ConfigException) {
//reload fail
errorMsg = "Insert failure.The reason is " + e.getMessage();
LOGGER.warn("Insert failure.The reason is ", e);
handleConfigException(e, service, managerTable);
} else {
service.writeErrMessage(ErrorCode.ER_YES, "unknown error:" + e.getMessage());
errorMsg = "unknown error:" + e.getMessage();
LOGGER.warn("unknown error:", e);
}
return;
} finally {
managerTable.deleteBackupFile();
managerTable.getLock().unlock();
}
writeOkPacket(1, rowSize, managerTable.getMsg(), service);
if (isSuccess) {
writeOkPacket(1, rowSize, managerTable.getMsg(), service);
} else {
service.writeErrMessage(ErrorCode.ER_YES, errorMsg);
}
}
private List<String> getColumn(MySqlInsertStatement insert, ManagerWritableTable managerTable, ManagerService service) {
@@ -180,9 +189,7 @@ public final class InsertHandler {
try {
managerTable.rollbackXmlFile();
} catch (IOException ioException) {
service.writeErrMessage(ErrorCode.ER_YES, "unknown error:" + e.getMessage());
return;
LOGGER.warn("unknown error:", e);
}
service.writeErrMessage(ErrorCode.ER_YES, "Insert failure.The reason is " + e.getMessage());
}
}
@@ -99,39 +99,51 @@ public final class UpdateHandler {
return;
}
int rowSize;
int rowSize = 0;
boolean lockFlag = managerTable.getLock().tryLock();
if (!lockFlag) {
service.writeErrMessage(ErrorCode.ER_YES, "Other threads are executing management commands(insert/update/delete), please try again later.");
return;
}
boolean isSuccess = true;
String errorMsg = null;
try {
List<RowDataPacket> foundRows = ManagerTableUtil.getFoundRows(service, managerTable, update.getWhere());
Set<LinkedHashMap<String, String>> affectPks = ManagerTableUtil.getAffectPks(service, managerTable, foundRows, values);
rowSize = updateRows(service, managerTable, affectPks, values);
} catch (SQLException e) {
service.writeErrMessage(StringUtil.isEmpty(e.getSQLState()) ? "HY000" : e.getSQLState(), e.getMessage(), e.getErrorCode());
return;
isSuccess = false;
errorMsg = e.getMessage();
} catch (ConfigException e) {
service.writeErrMessage(ErrorCode.ER_YES, "Update failure.The reason is " + e.getMessage());
return;
isSuccess = false;
errorMsg = "Update failure.The reason is " + e.getMessage();
} catch (Exception e) {
isSuccess = false;
if (e.getCause() instanceof ConfigException) {
//reload fail
errorMsg = "Update failure.The reason is " + e.getMessage();
LOGGER.warn("Update failure.The reason is ", e);
handleConfigException(e, service, managerTable);
} else {
service.writeErrMessage(ErrorCode.ER_YES, "unknown error:" + e.getMessage());
errorMsg = "unknown error:" + e.getMessage();
LOGGER.warn("unknown error:", e);
}
return;
} finally {
managerTable.deleteBackupFile();
managerTable.getLock().unlock();
}
OkPacket ok = new OkPacket();
ok.setPacketId(1);
ok.setAffectedRows(rowSize);
ok.write(service.getConnection());
writePacket(isSuccess, rowSize, service, errorMsg);
}
private void writePacket(boolean isSuccess, int rowSize, ManagerService service, String errorMsg) {
if (isSuccess) {
OkPacket ok = new OkPacket();
ok.setPacketId(1);
ok.setAffectedRows(rowSize);
ok.write(service.getConnection());
} else {
service.writeErrMessage(ErrorCode.ER_YES, errorMsg);
}
}
private int updateRows(ManagerService service, ManagerWritableTable managerTable, Set<LinkedHashMap<String, String>> affectPks, LinkedHashMap<String, String> values) throws Exception {
@@ -198,9 +210,7 @@ public final class UpdateHandler {
try {
managerTable.rollbackXmlFile();
} catch (IOException ioException) {
service.writeErrMessage(ErrorCode.ER_YES, "unknown error:" + e.getMessage());
return;
LOGGER.warn("unknown error:", e);
}
service.writeErrMessage(ErrorCode.ER_YES, "Update failure.The reason is " + e.getMessage());
}
}
@@ -23,6 +23,8 @@ import com.actiontech.dble.util.StringUtil;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLNullExpr;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.sql.SQLNonTransientException;
@@ -41,6 +43,11 @@ public final class ManagerTableUtil {
} else if (valueExpr instanceof SQLCharExpr) {
SQLCharExpr charExpr = (SQLCharExpr) valueExpr;
value = charExpr.getText();
if (StringUtil.isBlank(value) || StringUtil.equalsIgnoreCase(value, "null")) {
throw new SQLNonTransientException("Not Supported of Value EXPR :" + valueExpr.toString());
}
} else if (valueExpr instanceof SQLNullExpr) {
value = null;
} else {
throw new SQLNonTransientException("Not Supported of Value EXPR :" + valueExpr.toString());
}
@@ -98,8 +105,8 @@ public final class ManagerTableUtil {
String value = null == row.getValue(i) ? null : new String(row.getValue(i), charset);
affectPk.put(columnName, value);
if (null != values) {
boolean match = values.entrySet().stream().anyMatch(valueEntry -> !StringUtil.equals(affectPk.get(valueEntry.getKey()), valueEntry.getValue()));
if (!match) {
boolean isSkipRow = values.entrySet().stream().allMatch(valueEntry -> affectPk.containsKey(valueEntry.getKey()) && StringUtil.equals(affectPk.get(valueEntry.getKey()), valueEntry.getValue()));
if (isSkipRow) {
breakFlag = true;
break;
}
@@ -106,20 +106,24 @@ public abstract class ManagerWritableTable extends ManagerBaseTable {
for (SQLInsertStatement.ValuesClause valuesClause : values) {
List<SQLExpr> value = valuesClause.getValues();
LinkedHashMap<String, String> row = new LinkedHashMap<>();
int index = 0;
int index;
for (Map.Entry<String, ColumnMeta> column : columns.entrySet()) {
String columnName = column.getKey();
String insertColumn;
if (insertColumns.size() > index && columnName.equals(insertColumn = insertColumns.get(index))) {
String insertColumnVal = ManagerTableUtil.valueToString(value.get(index));
index = insertColumns.indexOf(columnName);
String insertColumnVal;
if (-1 != index && insertColumns.size() > index && columnName.equals(insertColumn = insertColumns.get(index))) {
insertColumnVal = ManagerTableUtil.valueToString(value.get(index));
if (this.notWritableColumnSet.contains(columnName) && !StringUtil.isEmpty(insertColumnVal)) {
throw new SQLException("Column '" + insertColumn + "' is not writable", "42S22", ErrorCode.ER_ERROR_ON_WRITE);
}
row.put(columnName, insertColumnVal);
index++;
if (null == insertColumnVal) {
insertColumnVal = column.getValue().getDefaultVal();
}
} else {
row.put(columnName, column.getValue().getDefaultVal());
insertColumnVal = column.getValue().getDefaultVal();
}
row.put(columnName, insertColumnVal);
}
lst.add(row);
}
@@ -152,7 +156,7 @@ public abstract class ManagerWritableTable extends ManagerBaseTable {
String pkValue = pk.toString();
if (pks.contains(pkValue)) {
throw new SQLException("Duplicate entry '" + pkValue + "' for key 'PRIMARY'", "23000", ErrorCode.ER_DUP_ENTRY);
} else {
} else if (!StringUtil.isBlank(pkValue) && !StringUtil.equalsIgnoreCase(pkValue, "null")) {
pks.add(pkValue);
}
}
@@ -196,4 +200,7 @@ public abstract class ManagerWritableTable extends ManagerBaseTable {
tempFile.delete();
}
}
public void afterExecute() {
}
}
@@ -9,19 +9,25 @@ import com.actiontech.dble.DbleServer;
import com.actiontech.dble.backend.datasource.PhysicalDbGroup;
import com.actiontech.dble.cluster.ClusterPathUtil;
import com.actiontech.dble.cluster.zkprocess.entity.DbGroups;
import com.actiontech.dble.cluster.zkprocess.entity.dbGroups.DBGroup;
import com.actiontech.dble.cluster.zkprocess.entity.dbGroups.HeartBeat;
import com.actiontech.dble.cluster.zkprocess.parse.XmlProcessBase;
import com.actiontech.dble.config.ConfigFileName;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.config.Fields;
import com.actiontech.dble.config.model.db.DbGroupConfig;
import com.actiontech.dble.config.util.ConfigException;
import com.actiontech.dble.meta.ColumnMeta;
import com.actiontech.dble.services.manager.information.ManagerSchemaInfo;
import com.actiontech.dble.services.manager.information.ManagerWritableTable;
import com.actiontech.dble.util.IntegerUtil;
import com.actiontech.dble.util.ResourceUtil;
import com.actiontech.dble.util.StringUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import javax.xml.bind.JAXBException;
import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.sql.SQLException;
import java.util.*;
@@ -121,17 +127,27 @@ public class DbleDbGroup extends ManagerWritableTable {
if (dbGroupRows.isEmpty()) {
return affectPks.size();
}
XmlProcessBase xmlProcess = new XmlProcessBase();
DbleDbInstance dbleDbInstance = (DbleDbInstance) ManagerSchemaInfo.getInstance().getTables().get(DbleDbInstance.TABLE_NAME);
DbGroups dbs = dbleDbInstance.transformRow(xmlProcess, dbGroupRows, null);
List<DBGroup> dbGroupList = affectPks.stream().map(this::transformRowToDBGroup).collect(Collectors.toList());
dbs.encryptPassword();
xmlProcess.writeObjToXml(dbs, getXmlFilePath(), "db");
DbGroups dbGroups = getDbGroups();
for (DBGroup dbGroup : dbGroupList) {
Optional<DBGroup> dbGroupOp = dbGroups.getDbGroup().stream().filter(sourceDbGroup -> StringUtil.equals(sourceDbGroup.getName(), dbGroup.getName())).findFirst();
if (!dbGroupOp.isPresent()) {
String msg = String.format("this row[%s] does not exist.", dbGroup.getName());
throw new SQLException(msg, "42S22", ErrorCode.ER_NO_REFERENCED_ROW_2);
}
dbGroup.setDbInstance(dbGroupOp.get().getDbInstance());
dbGroups.getDbGroup().removeIf(sourceDbGroup -> StringUtil.equals(sourceDbGroup.getName(), dbGroup.getName()));
dbGroups.getDbGroup().add(dbGroup);
}
DbleDbGroup.saveDbGroups(dbGroups, getXmlFilePath());
return affectPks.size();
}
@Override
public int deleteRows(Set<LinkedHashMap<String, String>> affectPks) throws SQLException {
public int deleteRows(Set<LinkedHashMap<String, String>> affectPks) {
//check
checkDeleteRule(affectPks);
//temp
@@ -146,18 +162,65 @@ public class DbleDbGroup extends ManagerWritableTable {
return affectPks.size();
}
XmlProcessBase xmlProcess = new XmlProcessBase();
DbleDbInstance dbleDbInstance = (DbleDbInstance) ManagerSchemaInfo.getInstance().getTables().get(DbleDbInstance.TABLE_NAME);
DbGroups dbs = dbleDbInstance.transformRow(xmlProcess, null, null);
DbGroups dbGroups = getDbGroups();
for (LinkedHashMap<String, String> affectPk : dbGroupRows) {
dbs.getDbGroup().removeIf(dbGroup -> StringUtil.equals(dbGroup.getName(), affectPk.get(COLUMN_NAME)));
dbGroups.getDbGroup().removeIf(dbGroup -> StringUtil.equals(dbGroup.getName(), affectPk.get(COLUMN_NAME)));
}
dbs.encryptPassword();
xmlProcess.writeObjToXml(dbs, getXmlFilePath(), "db");
DbleDbGroup.saveDbGroups(dbGroups, getXmlFilePath());
return affectPks.size();
}
public DBGroup transformRowToDBGroup(LinkedHashMap<String, String> values) {
DBGroup dbGroup = new DBGroup();
HeartBeat heartbeat = new HeartBeat();
dbGroup.setHeartbeat(heartbeat);
for (Map.Entry<String, String> latestVal : values.entrySet()) {
String key = latestVal.getKey();
String value = latestVal.getValue();
switch (key) {
case COLUMN_NAME:
dbGroup.setName(value);
break;
case COLUMN_HEARTBEAT_STMT:
heartbeat.setValue(value);
break;
case COLUMN_HEARTBEAT_TIMEOUT:
heartbeat.setTimeout(Integer.parseInt(value));
break;
case COLUMN_HEARTBEAT_RETRY:
heartbeat.setErrorRetryCount(Integer.parseInt(value));
break;
case COLUMN_RW_SPLIT_MODE:
dbGroup.setRwSplitMode(Integer.parseInt(value));
break;
case COLUMN_DELAY_THRESHOLD:
dbGroup.setDelayThreshold(Integer.parseInt(value));
break;
case COLUMN_DISABLE_HA:
dbGroup.setDisableHA(value);
break;
default:
break;
}
}
return dbGroup;
}
public static void saveDbGroups(DbGroups dbGroups, String xmlFilePath) {
XmlProcessBase xmlProcess = new XmlProcessBase();
xmlProcess.addParseClass(DbGroups.class);
try {
xmlProcess.initJaxbClass();
} catch (JAXBException e) {
throw new ConfigException(e);
}
//write to configuration
xmlProcess.writeObjToXml(dbGroups, xmlFilePath, "db");
}
private void checkDeleteRule(Set<LinkedHashMap<String, String>> affectPks) {
for (LinkedHashMap<String, String> affectPk : affectPks) {
//check user-group
@@ -187,32 +250,54 @@ public class DbleDbGroup extends ManagerWritableTable {
private void checkRule(LinkedHashMap<String, String> row) {
if (null != row && !row.isEmpty()) {
String delayThresholdStr = row.get(COLUMN_DELAY_THRESHOLD);
int delayThreshold = StringUtil.isEmpty(delayThresholdStr) ? 0 : Integer.parseInt(delayThresholdStr);
String disableHaStr = row.get(COLUMN_DISABLE_HA);
if (!StringUtil.isEmpty(disableHaStr) && !StringUtil.equalsIgnoreCase(disableHaStr, Boolean.FALSE.toString()) &&
!StringUtil.equalsIgnoreCase(disableHaStr, Boolean.TRUE.toString())) {
throw new ConfigException("Column 'disable_ha' values only support 'false' or 'true'.");
}
boolean disableHa = !StringUtil.isEmpty(disableHaStr) && Boolean.parseBoolean(disableHaStr);
String rwSplitModeStr = row.get(COLUMN_RW_SPLIT_MODE);
int rwSplitMode = StringUtil.isEmpty(rwSplitModeStr) ? 0 : Integer.parseInt(rwSplitModeStr);
String heartbeatTimeoutStr = row.get(COLUMN_HEARTBEAT_TIMEOUT);
int heartbeatTimeout = StringUtil.isEmpty(heartbeatTimeoutStr) ? 0 : Integer.parseInt(heartbeatTimeoutStr);
String heartbeatRetryStr = row.get(COLUMN_HEARTBEAT_RETRY);
int heartbeatRetry = StringUtil.isEmpty(heartbeatRetryStr) ? 0 : Integer.parseInt(heartbeatRetryStr);
DbGroupConfig dbGroupConfig = new DbGroupConfig(row.get(COLUMN_NAME), null, null, delayThreshold, disableHa);
dbGroupConfig.setRwSplitMode(rwSplitMode);
dbGroupConfig.setHeartbeatSQL(row.get(COLUMN_HEARTBEAT_STMT));
dbGroupConfig.setHeartbeatTimeout(heartbeatTimeout * 1000);
dbGroupConfig.setErrorRetryCount(heartbeatRetry);
LinkedHashMap<String, String> map = initMap(dbGroupConfig);
for (Map.Entry<String, String> entry : map.entrySet()) {
if (row.containsKey(entry.getKey())) {
row.put(entry.getKey(), entry.getValue());
if (row.containsKey(COLUMN_DISABLE_HA) && !StringUtil.isEmpty(row.get(COLUMN_DISABLE_HA))) {
String disableHaStr = row.get(COLUMN_DISABLE_HA);
if (!StringUtil.equalsIgnoreCase(disableHaStr, Boolean.FALSE.toString()) &&
!StringUtil.equalsIgnoreCase(disableHaStr, Boolean.TRUE.toString())) {
throw new ConfigException("Column 'disable_ha' values only support 'false' or 'true'.");
}
}
if (row.containsKey(COLUMN_RW_SPLIT_MODE) && !StringUtil.isEmpty(row.get(COLUMN_RW_SPLIT_MODE))) {
String rwSplitModeStr = row.get(COLUMN_RW_SPLIT_MODE);
if (!StringUtil.isBlank(rwSplitModeStr)) {
int rwSplitMode = IntegerUtil.parseInt(rwSplitModeStr);
if (rwSplitMode > 2 || rwSplitMode < 0) {
throw new ConfigException("rwSplitMode should be between 0 and 2!");
}
}
}
checkInterValue(row);
}
}
public static DbGroups getDbGroups() {
XmlProcessBase xmlProcess = new XmlProcessBase();
DbGroups dbs = null;
try {
xmlProcess.addParseClass(DbGroups.class);
xmlProcess.initJaxbClass();
dbs = (DbGroups) xmlProcess.baseParseXmlToBean(ConfigFileName.DB_XML);
} catch (JAXBException | XMLStreamException e) {
e.printStackTrace();
}
if (null == dbs) {
throw new ConfigException("configuration is empty");
}
return dbs;
}
private void checkInterValue(LinkedHashMap<String, String> row) {
String delayThresholdStr = row.get(COLUMN_DELAY_THRESHOLD);
String heartbeatTimeoutStr = row.get(COLUMN_HEARTBEAT_TIMEOUT);
String heartbeatRetryStr = row.get(COLUMN_HEARTBEAT_RETRY);
if (row.containsKey(COLUMN_DELAY_THRESHOLD) && (StringUtil.isBlank(delayThresholdStr) || IntegerUtil.parseInt(delayThresholdStr) < -1)) {
throw new ConfigException("Column '" + COLUMN_DELAY_THRESHOLD + "' should be an integer greater than or equal to -1!");
}
if (row.containsKey(COLUMN_HEARTBEAT_TIMEOUT) && (StringUtil.isBlank(heartbeatTimeoutStr) || IntegerUtil.parseInt(heartbeatTimeoutStr) < 0)) {
throw new ConfigException("Column '" + COLUMN_HEARTBEAT_TIMEOUT + "' should be an integer greater than or equal to 0!");
}
if (row.containsKey(COLUMN_HEARTBEAT_RETRY) && (StringUtil.isBlank(heartbeatRetryStr) || IntegerUtil.parseInt(heartbeatRetryStr) < 0)) {
throw new ConfigException("Column '" + COLUMN_HEARTBEAT_RETRY + "' should be an integer greater than or equal to 0!");
}
}
@@ -7,40 +7,29 @@ package com.actiontech.dble.services.manager.information.tables;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.backend.datasource.PhysicalDbGroup;
import com.actiontech.dble.backend.datasource.PhysicalDbInstance;
import com.actiontech.dble.backend.heartbeat.MySQLHeartbeat;
import com.actiontech.dble.backend.mysql.nio.MySQLInstance;
import com.actiontech.dble.cluster.ClusterPathUtil;
import com.actiontech.dble.cluster.zkprocess.entity.DbGroups;
import com.actiontech.dble.cluster.zkprocess.entity.Property;
import com.actiontech.dble.cluster.zkprocess.entity.dbGroups.DBGroup;
import com.actiontech.dble.cluster.zkprocess.entity.dbGroups.DBInstance;
import com.actiontech.dble.cluster.zkprocess.entity.dbGroups.HeartBeat;
import com.actiontech.dble.cluster.zkprocess.parse.XmlProcessBase;
import com.actiontech.dble.config.ConfigFileName;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.config.Fields;
import com.actiontech.dble.config.model.db.DbGroupConfig;
import com.actiontech.dble.config.model.db.DbInstanceConfig;
import com.actiontech.dble.config.model.db.PoolConfig;
import com.actiontech.dble.config.util.ConfigException;
import com.actiontech.dble.config.util.ParameterMapping;
import com.actiontech.dble.meta.ColumnMeta;
import com.actiontech.dble.services.manager.information.ManagerSchemaInfo;
import com.actiontech.dble.services.manager.information.ManagerWritableTable;
import com.actiontech.dble.services.manager.response.ShowHeartbeat;
import com.actiontech.dble.util.DecryptUtil;
import com.actiontech.dble.util.ResourceUtil;
import com.actiontech.dble.util.StringUtil;
import com.actiontech.dble.util.*;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import javax.xml.bind.JAXBException;
import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
@@ -112,7 +101,7 @@ public class DbleDbInstance extends ManagerWritableTable {
private static final String COLUMN_HEARTBEAT_PERIOD_MILLIS = "heartbeat_period_millis";
public DbleDbInstance() {
super(TABLE_NAME, 30);
super(TABLE_NAME, 33);
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);
@@ -269,98 +258,181 @@ public class DbleDbInstance extends ManagerWritableTable {
@Override
public int insertRows(List<LinkedHashMap<String, String>> rows) throws SQLException {
return insertOrUpdate(rows, true);
}
List<DBInstance> dbInstanceList = rows.stream().map(this::transformRowToDBInstance).collect(Collectors.toList());
DbGroups dbGroups = DbleDbGroup.getDbGroups();
private int insertOrUpdate(List<LinkedHashMap<String, String>> rows, boolean insertFlag) throws SQLException {
decryptPassword(rows, insertFlag);
final int size = rows.size();
XmlProcessBase xmlProcess = new XmlProcessBase();
DbGroups dbs = transformRow(xmlProcess, null, rows);
//check logical foreign key
if (!rows.isEmpty()) {
String msg = String.format("Cannot add or update a child row: a logical foreign key '%s' constraint fails", COLUMN_DB_GROUP);
throw new SQLException(msg, "42S22", ErrorCode.ER_NO_REFERENCED_ROW_2);
}
//check primary
for (DBGroup group : dbs.getDbGroup()) {
long primaryCount = group.getDbInstance().stream().filter(dbInstance -> null != dbInstance.getPrimary() && dbInstance.getPrimary()).count();
if (primaryCount != 1) {
String msg = String.format("dbGroup[%s] has one and only one primary instance", group.getName());
throw new ConfigException(msg);
}
}
//check connection
checkInstanceConnection(dbs);
//remove temp row
DbleDbGroup dbleDbGroup = (DbleDbGroup) ManagerSchemaInfo.getInstance().getTables().get(DbleDbGroup.TABLE_NAME);
for (DBGroup dbGroup : dbs.getDbGroup()) {
dbleDbGroup.getTempRowList().removeIf(group -> StringUtil.equals(group.get(DbleDbGroup.COLUMN_NAME), dbGroup.getName()));
}
dbs.encryptPassword();
//write to configuration
xmlProcess.writeObjToXml(dbs, getXmlFilePath(), "db");
return size;
}
List<LinkedHashMap<String, String>> tempDbGroupMapList = dbleDbGroup.getTempRowList();
List<DBGroup> tempDbGroupList = tempDbGroupMapList.stream().map(dbleDbGroup::transformRowToDBGroup).collect(Collectors.toList());
for (DBInstance dbInstance : dbInstanceList) {
Optional<DBGroup> dbGroupOp = dbGroups.getDbGroup().stream().filter(dbGroup -> StringUtil.equals(dbGroup.getName(), dbInstance.getDbGroup())).findFirst();
if (!dbGroupOp.isPresent()) {
dbGroupOp = tempDbGroupList.stream().filter(dbGroup -> StringUtil.equals(dbGroup.getName(), dbInstance.getDbGroup())).findFirst();
if (!dbGroupOp.isPresent()) {
String msg = String.format("Cannot add or update a child row: a logical foreign key '%s':%s constraint fails", COLUMN_DB_GROUP, dbInstance.getDbGroup());
throw new SQLException(msg, "42S22", ErrorCode.ER_NO_REFERENCED_ROW_2);
}
dbGroups.addDbGroup(dbGroupOp.get());
}
dbGroupOp.get().addDbInstance(dbInstance);
}
DbleDbGroup.saveDbGroups(dbGroups, getXmlFilePath());
return rows.size();
}
@Override
public int updateRows(Set<LinkedHashMap<String, String>> affectPks, LinkedHashMap<String, String> values) throws SQLException {
affectPks.forEach(affectPk -> affectPk.putAll(values));
return insertOrUpdate(Lists.newArrayList(affectPks), false);
affectPks.forEach(affectPk -> {
if (Boolean.FALSE.toString().equalsIgnoreCase(affectPk.get(COLUMN_ENCRYPT_CONFIGURED))) {
String password = DecryptUtil.dbHostDecrypt(true, affectPk.get(COLUMN_NAME), affectPk.get(COLUMN_USER), affectPk.get(COLUMN_PASSWORD_ENCRYPT));
affectPk.put(COLUMN_PASSWORD_ENCRYPT, password);
}
affectPk.putAll(values);
});
List<DBInstance> dbInstanceList = affectPks.stream().map(this::transformRowToDBInstance).collect(Collectors.toList());
DbGroups dbGroups = DbleDbGroup.getDbGroups();
for (DBInstance dbInstance : dbInstanceList) {
Optional<DBGroup> dbGroupOp = dbGroups.getDbGroup().stream().filter(dbGroup -> StringUtil.equals(dbGroup.getName(), dbInstance.getDbGroup())).findFirst();
if (!dbGroupOp.isPresent()) {
String msg = String.format("Cannot add or update a child row: a logical foreign key '%s':%s constraint fails", COLUMN_DB_GROUP, dbInstance.getDbGroup());
throw new SQLException(msg, "42S22", ErrorCode.ER_NO_REFERENCED_ROW_2);
}
dbGroupOp.get().getDbInstance().removeIf(sourceDbInstance -> StringUtil.equals(sourceDbInstance.getName(), dbInstance.getName()));
dbGroupOp.get().addDbInstance(dbInstance);
}
DbleDbGroup.saveDbGroups(dbGroups, getXmlFilePath());
return affectPks.size();
}
@Override
public int deleteRows(Set<LinkedHashMap<String, String>> affectPks) throws SQLException {
XmlProcessBase xmlProcess = new XmlProcessBase();
DbGroups dbGroups = transformRow(xmlProcess, null, null);
for (LinkedHashMap<String, String> affectPk : affectPks) {
for (DBGroup dbGroup : dbGroups.getDbGroup()) {
dbGroup.getDbInstance().removeIf(dbInstance -> StringUtil.equals(affectPk.get(COLUMN_DB_GROUP), dbGroup.getName()) && StringUtil.equals(affectPk.get(COLUMN_NAME), dbInstance.getName()));
List<DBInstance> dbInstanceList = affectPks.stream().map(this::transformRowToDBInstance).collect(Collectors.toList());
DbGroups dbGroups = DbleDbGroup.getDbGroups();
for (DBInstance dbInstance : dbInstanceList) {
Optional<DBGroup> dbGroupOp = dbGroups.getDbGroup().stream().filter(dbGroup -> StringUtil.equals(dbGroup.getName(), dbInstance.getDbGroup())).findFirst();
if (!dbGroupOp.isPresent()) {
String msg = String.format("Cannot add or update a child row: a logical foreign key '%s':%s constraint fails", COLUMN_DB_GROUP, dbInstance.getDbGroup());
throw new SQLException(msg, "42S22", ErrorCode.ER_NO_REFERENCED_ROW_2);
}
dbGroupOp.get().getDbInstance().removeIf(sourceDbInstance -> StringUtil.equals(sourceDbInstance.getName(), dbInstance.getName()));
}
for (DBGroup dbGroup : dbGroups.getDbGroup()) {
boolean existPrimary = dbGroup.getDbInstance().stream().anyMatch(dbInstance -> null != dbInstance.getPrimary() && dbInstance.getPrimary());
if (!existPrimary && !dbGroup.getDbInstance().isEmpty()) {
throw new SQLException("Table dble_db_group[" + dbGroup.getName() + "] needs to retain a primary dbInstance", "42S22", ErrorCode.ER_YES);
}
}
Set<DBGroup> removeDBGroupSet = dbGroups.getDbGroup().stream().filter(dbGroup -> dbGroup.getDbInstance().isEmpty()).collect(Collectors.toSet());
//check remove empty instance
checkDeleteRule(removeDBGroupSet);
//remove empty instance
dbGroups.getDbGroup().removeIf(dbGroup -> dbGroup.getDbInstance().isEmpty());
dbGroups.encryptPassword();
//write to configuration
xmlProcess.writeObjToXml(dbGroups, getXmlFilePath(), "db");
DbleDbGroup.saveDbGroups(dbGroups, getXmlFilePath());
return affectPks.size();
}
private void checkDeleteRule(Set<DBGroup> removeDBGroupSet) {
for (DBGroup dbGroup : removeDBGroupSet) {
//check user-group
DbleRwSplitEntry dbleRwSplitEntry = (DbleRwSplitEntry) ManagerSchemaInfo.getInstance().getTables().get(DbleRwSplitEntry.TABLE_NAME);
boolean existUser = dbleRwSplitEntry.getRows().stream().anyMatch(entry -> entry.get(DbleRwSplitEntry.COLUMN_DB_GROUP).equals(dbGroup.getName()));
if (existUser) {
throw new ConfigException("Cannot delete or update a parent row: a foreign key constraint fails `dble_db_user`(`db_group`) REFERENCES `dble_db_group`(`name`)");
}
//check sharding_node-group
DbleShardingNode dbleShardingNode = (DbleShardingNode) ManagerSchemaInfo.getInstance().getTables().get(DbleShardingNode.TABLE_NAME);
boolean existShardingNode = dbleShardingNode.getRows().stream().anyMatch(entry -> entry.get(DbleShardingNode.COLUMN_DB_GROUP).equals(dbGroup.getName()));
if (existShardingNode) {
throw new ConfigException("Cannot delete or update a parent row: a foreign key constraint fails `dble_sharding_node`(`db_group`) REFERENCES `dble_db_group`(`name`)");
}
@Override
public void afterExecute() {
//remove temp dbGroup
DbGroups dbGroups = DbleDbGroup.getDbGroups();
DbleDbGroup dbleDbGroup = (DbleDbGroup) ManagerSchemaInfo.getInstance().getTables().get(DbleDbGroup.TABLE_NAME);
for (DBGroup dbGroup : dbGroups.getDbGroup()) {
dbleDbGroup.getTempRowList().removeIf(group -> StringUtil.equals(group.get(DbleDbGroup.COLUMN_NAME), dbGroup.getName()));
}
}
private void decryptPassword(List<LinkedHashMap<String, String>> rows, boolean insertFlag) {
for (LinkedHashMap<String, String> row : rows) {
checkBooleanVal(row);
if ((insertFlag && Boolean.parseBoolean(row.get(COLUMN_ENCRYPT_CONFIGURED))) || !insertFlag) {
row.put(COLUMN_PASSWORD_ENCRYPT, DecryptUtil.dbHostDecrypt(true, row.get(COLUMN_NAME),
row.get(COLUMN_USER), row.get(COLUMN_PASSWORD_ENCRYPT)));
private DBInstance transformRowToDBInstance(LinkedHashMap<String, String> map) {
if (null == map || map.isEmpty()) {
return null;
}
checkBooleanVal(map);
DBInstance dbInstance = new DBInstance();
StringBuilder url = new StringBuilder();
List<Property> propertyList = Lists.newArrayList();
String key;
String entryValue;
for (Map.Entry<String, String> entry : map.entrySet()) {
switch (entry.getKey()) {
case COLUMN_NAME:
dbInstance.setName(entry.getValue());
break;
case COLUMN_DB_GROUP:
dbInstance.setDbGroup(entry.getValue());
break;
case COLUMN_ADDR:
case COLUMN_PORT:
url.append(entry.getValue()).append(":");
break;
case COLUMN_USER:
dbInstance.setUser(entry.getValue());
break;
case COLUMN_PASSWORD_ENCRYPT:
dbInstance.setPassword(entry.getValue());
break;
case COLUMN_ENCRYPT_CONFIGURED:
dbInstance.setUsingDecrypt(entry.getValue());
break;
case COLUMN_PRIMARY:
dbInstance.setPrimary(!StringUtil.isEmpty(entry.getValue()) && Boolean.parseBoolean(entry.getValue()));
break;
case COLUMN_DISABLED:
dbInstance.setDisabled(entry.getValue());
break;
case COLUMN_MIN_CONN_COUNT:
if (!StringUtil.isBlank(entry.getValue())) {
dbInstance.setMinCon(IntegerUtil.parseInt(entry.getValue()));
}
if (dbInstance.getMinCon() < 0) {
throw new ConfigException("Column 'min_conn_count' value cannot be less than 0.");
}
break;
case COLUMN_MAX_CONN_COUNT:
if (!StringUtil.isBlank(entry.getValue())) {
dbInstance.setMaxCon(IntegerUtil.parseInt(entry.getValue()));
}
if (dbInstance.getMaxCon() < 0) {
throw new ConfigException("Column 'max_conn_count' value cannot be less than 0.");
}
break;
case COLUMN_READ_WEIGHT:
if (IntegerUtil.parseInt(Optional.ofNullable(entry.getValue()).orElse("0")) < 0) {
throw new ConfigException("readWeight attribute in dbInstance[" + map.get(COLUMN_NAME) + "] can't be less than 0!");
}
dbInstance.setReadWeight(entry.getValue());
break;
case COLUMN_ID:
dbInstance.setId(entry.getValue());
break;
case COLUMN_TEST_ON_CREATE:
case COLUMN_TEST_ON_BORROW:
case COLUMN_TEST_ON_RETURN:
case COLUMN_TEST_WHILE_IDLE:
key = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, entry.getKey());
entryValue = entry.getValue();
if (StringUtil.isBlank(entryValue) || (!StringUtil.equalsIgnoreCase(entryValue, Boolean.FALSE.toString()) && !StringUtil.equalsIgnoreCase(entryValue, Boolean.TRUE.toString()))) {
throw new ConfigException("Column '" + entry.getKey() + "' values only support 'false' or 'true'.");
}
propertyList.add(new Property(entryValue, key));
break;
case COLUMN_CONNECTION_TIMEOUT:
case COLUMN_CONNECTION_HEARTBEAT_TIMEOUT:
case COLUMN_TIME_BETWEEN_EVICTION_RUNS_MILLIS:
case COLUMN_IDLE_TIMEOUT:
case COLUMN_HEARTBEAT_PERIOD_MILLIS:
case COLUMN_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS:
key = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, entry.getKey());
entryValue = entry.getValue();
if (StringUtil.isBlank(entryValue)) {
throw new ConfigException("Column '" + entry.getKey() + "' should be an integer greater than 0!");
}
if (!LongUtil.isLong(entryValue)) {
throw new ConfigException("property [ " + entry.getKey() + " ] '" + entryValue + "' data type should be long");
} else if (LongUtil.parseLong(entryValue) <= 0) {
throw new ConfigException("property [ " + entry.getKey() + " ] '" + entryValue + "' should be an integer greater than 0!");
}
propertyList.add(new Property(entryValue, key));
break;
default:
break;
}
}
dbInstance.setUrl(url.substring(0, url.length() - 1));
dbInstance.setProperty(propertyList);
return dbInstance;
}
private void checkBooleanVal(LinkedHashMap<String, String> row) {
@@ -369,187 +441,13 @@ public class DbleDbInstance extends ManagerWritableTable {
for (String key : keySet) {
if (row.containsKey(key) && !StringUtil.isEmpty(row.get(key))) {
String value = row.get(key);
if (!StringUtil.equalsIgnoreCase(value, Boolean.FALSE.toString()) && !StringUtil.equalsIgnoreCase(value, Boolean.TRUE.toString())) {
if (StringUtil.isBlank(value) || !StringUtil.equalsIgnoreCase(value, Boolean.FALSE.toString()) && !StringUtil.equalsIgnoreCase(value, Boolean.TRUE.toString())) {
throw new ConfigException("Column '" + key + "' values only support 'false' or 'true'.");
}
}
}
}
public DbGroups transformRow(XmlProcessBase xmlProcess, List<LinkedHashMap<String, String>> changeDbGroupRows, List<LinkedHashMap<String, String>> changeDbInstanceRows) {
if (null == xmlProcess) {
return null;
}
DbGroups dbs = null;
try {
xmlProcess.addParseClass(DbGroups.class);
xmlProcess.initJaxbClass();
dbs = (DbGroups) xmlProcess.baseParseXmlToBean(ConfigFileName.DB_XML);
} catch (JAXBException | XMLStreamException e) {
e.printStackTrace();
}
if (null == dbs) {
throw new ConfigException("configuration is empty");
}
for (DBGroup dbGroup : dbs.getDbGroup()) {
for (DBInstance dbInstance : dbGroup.getDbInstance()) {
String usingDecrypt = dbInstance.getUsingDecrypt();
if (!StringUtil.isEmpty(usingDecrypt) && Boolean.parseBoolean(usingDecrypt)) {
dbInstance.setPassword(DecryptUtil.dbHostDecrypt(true, dbInstance.getName(), dbInstance.getUser(), dbInstance.getPassword()));
}
}
}
DbleDbGroup dbleDbGroup = (DbleDbGroup) ManagerSchemaInfo.getInstance().getTables().get(DbleDbGroup.TABLE_NAME);
List<LinkedHashMap<String, String>> dbGroupRowList = dbleDbGroup.getRows();
for (LinkedHashMap<String, String> dbGroupRow : dbGroupRowList) {
DBGroup dbGroup = initDBGroup(dbGroupRow, changeDbGroupRows, dbs);
initDBInstance(dbGroupRow, changeDbInstanceRows, dbGroup);
dbs.addDbGroup(dbGroup);
}
dbs.getDbGroup().removeIf(dbGroup -> null == dbGroup.getDbInstance() || dbGroup.getDbInstance().isEmpty());
return dbs;
}
private void initDBInstance(LinkedHashMap<String, String> dbGroupRow, List<LinkedHashMap<String, String>> changeDbInstanceRows, DBGroup dbGroup) {
if (null == changeDbInstanceRows) {
return;
}
List<LinkedHashMap<String, String>> instanceRowList = changeDbInstanceRows.stream().filter(row -> StringUtil.equals(dbGroupRow.get(DbleDbGroup.COLUMN_NAME), row.get(COLUMN_DB_GROUP))).collect(Collectors.toList());
if (!instanceRowList.isEmpty()) {
instanceRowList.forEach(instanceRowMap -> {
List<Property> propertyList = Lists.newArrayList();
String testOnCreate = instanceRowMap.get(COLUMN_TEST_ON_CREATE);
if (!StringUtil.isEmpty(testOnCreate)) {
propertyList.add(new Property(testOnCreate, "testOnCreate"));
}
String testOnBorrow = instanceRowMap.get(COLUMN_TEST_ON_BORROW);
if (!StringUtil.isEmpty(testOnBorrow)) {
propertyList.add(new Property(testOnBorrow, "testOnBorrow"));
}
String testOnReturn = instanceRowMap.get(COLUMN_TEST_ON_RETURN);
if (!StringUtil.isEmpty(testOnReturn)) {
propertyList.add(new Property(testOnReturn, "testOnReturn"));
}
String testWhileIdle = instanceRowMap.get(COLUMN_TEST_WHILE_IDLE);
if (!StringUtil.isEmpty(testWhileIdle)) {
propertyList.add(new Property(testWhileIdle, "testWhileIdle"));
}
String connectionTimeout = instanceRowMap.get(COLUMN_CONNECTION_TIMEOUT);
if (!StringUtil.isEmpty(connectionTimeout)) {
propertyList.add(new Property(connectionTimeout, "connectionTimeout"));
}
String connectionHeartbeatTimeout = instanceRowMap.get(COLUMN_CONNECTION_HEARTBEAT_TIMEOUT);
if (!StringUtil.isEmpty(connectionHeartbeatTimeout)) {
propertyList.add(new Property(connectionHeartbeatTimeout, "connectionHeartbeatTimeout"));
}
String timeBetweenEvictionRunsMillis = instanceRowMap.get(COLUMN_TIME_BETWEEN_EVICTION_RUNS_MILLIS);
if (!StringUtil.isEmpty(timeBetweenEvictionRunsMillis)) {
propertyList.add(new Property(timeBetweenEvictionRunsMillis, "timeBetweenEvictionRunsMillis"));
}
String idleTimeout = instanceRowMap.get(COLUMN_IDLE_TIMEOUT);
if (!StringUtil.isEmpty(idleTimeout)) {
propertyList.add(new Property(idleTimeout, "idleTimeout"));
}
String heartbeatPeriodMillis = instanceRowMap.get(COLUMN_HEARTBEAT_PERIOD_MILLIS);
if (!StringUtil.isEmpty(heartbeatPeriodMillis)) {
propertyList.add(new Property(heartbeatPeriodMillis, "heartbeatPeriodMillis"));
}
String evictorShutdownTimeoutMillis = instanceRowMap.get(COLUMN_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS);
if (!StringUtil.isEmpty(evictorShutdownTimeoutMillis)) {
propertyList.add(new Property(evictorShutdownTimeoutMillis, "evictorShutdownTimeoutMillis"));
}
Integer maxCon = StringUtil.isEmpty(instanceRowMap.get(COLUMN_MAX_CONN_COUNT)) ? null : Integer.valueOf(instanceRowMap.get(COLUMN_MAX_CONN_COUNT));
Integer minCon = StringUtil.isEmpty(instanceRowMap.get(COLUMN_MIN_CONN_COUNT)) ? null : Integer.valueOf(instanceRowMap.get(COLUMN_MIN_CONN_COUNT));
Boolean primary = StringUtil.isEmpty(instanceRowMap.get(COLUMN_PRIMARY)) ? null : Boolean.valueOf(instanceRowMap.get(COLUMN_PRIMARY));
DBInstance dbInstance = new DBInstance(instanceRowMap.get(COLUMN_NAME), instanceRowMap.get(COLUMN_ADDR) + ":" + instanceRowMap.get(COLUMN_PORT),
instanceRowMap.get(COLUMN_PASSWORD_ENCRYPT), instanceRowMap.get(COLUMN_USER), maxCon, minCon, instanceRowMap.get(COLUMN_DISABLED),
instanceRowMap.get(COLUMN_ID), instanceRowMap.get(COLUMN_READ_WEIGHT), primary, propertyList, instanceRowMap.get(COLUMN_ENCRYPT_CONFIGURED));
if (dbGroup.getDbInstance().stream().anyMatch(instance -> StringUtil.equals(instance.getName(), dbInstance.getName()))) {
dbGroup.getDbInstance().removeIf(instance -> StringUtil.equals(instance.getName(), dbInstance.getName()));
}
dbGroup.addDbInstance(dbInstance);
changeDbInstanceRows.remove(instanceRowMap);
});
}
}
private DBGroup initDBGroup(LinkedHashMap<String, String> dbGroupRow, List<LinkedHashMap<String, String>> changeDbGroupRows, DbGroups dbs) {
changeDbGroupRows = null != changeDbGroupRows ? changeDbGroupRows : Lists.newArrayList();
LinkedHashMap<String, String> finalDbGroupRow = dbGroupRow;
Optional<LinkedHashMap<String, String>> changeDbGroupRow = changeDbGroupRows.stream().filter(changeGroupRow -> StringUtil.equals(changeGroupRow.get(DbleDbGroup.COLUMN_NAME), finalDbGroupRow.get(COLUMN_NAME))).findFirst();
if (changeDbGroupRow.isPresent()) {
dbGroupRow = changeDbGroupRow.get();
}
Integer timeout = StringUtil.isEmpty(dbGroupRow.get(DbleDbGroup.COLUMN_HEARTBEAT_TIMEOUT)) ? null : Integer.valueOf(dbGroupRow.get(DbleDbGroup.COLUMN_HEARTBEAT_TIMEOUT));
Integer errorRetryCount = StringUtil.isEmpty(dbGroupRow.get(DbleDbGroup.COLUMN_HEARTBEAT_RETRY)) ? null : Integer.valueOf(dbGroupRow.get(DbleDbGroup.COLUMN_HEARTBEAT_RETRY));
Integer rwSplitMode = StringUtil.isEmpty(dbGroupRow.get(DbleDbGroup.COLUMN_RW_SPLIT_MODE)) ? null : Integer.valueOf(dbGroupRow.get(DbleDbGroup.COLUMN_RW_SPLIT_MODE));
Integer delayThreshold = StringUtil.isEmpty(dbGroupRow.get(DbleDbGroup.COLUMN_DELAY_THRESHOLD)) ? null : Integer.valueOf(dbGroupRow.get(DbleDbGroup.COLUMN_DELAY_THRESHOLD));
HeartBeat heartBeat = new HeartBeat(dbGroupRow.get(DbleDbGroup.COLUMN_HEARTBEAT_STMT), timeout, errorRetryCount);
DBGroup dbGroup = new DBGroup(rwSplitMode, dbGroupRow.get(DbleDbGroup.COLUMN_NAME), delayThreshold, dbGroupRow.get(DbleDbGroup.COLUMN_DISABLE_HA), heartBeat);
Optional<DBGroup> first = dbs.getDbGroup().stream().filter(group -> StringUtil.equals(group.getName(), dbGroup.getName())).findFirst();
if (first.isPresent()) {
DBGroup oldDbGroup = first.get();
dbs.getDbGroup().removeIf(group -> StringUtil.equals(group.getName(), dbGroup.getName()));
dbGroup.addAllDbInstance(oldDbGroup.getDbInstance());
}
return dbGroup;
}
private void checkInstanceConnection(DbGroups dbs) {
try {
for (DBGroup dbGroup : dbs.getDbGroup()) {
List<DBInstance> dbInstanceList = dbGroup.getDbInstance();
DbInstanceConfig tmpDbInstanceConfig = null;
List<DbInstanceConfig> dbInstanceConfigList = Lists.newArrayList();
for (DBInstance dbInstance : dbInstanceList) {
String url = dbInstance.getUrl();
int colonIndex = url.indexOf(':');
String ip = url.substring(0, colonIndex).trim();
int port = Integer.parseInt(url.substring(colonIndex + 1).trim());
boolean disabled = !StringUtil.isEmpty(dbInstance.getDisabled()) && Boolean.parseBoolean(dbInstance.getDisabled());
int readWeight = StringUtil.isEmpty(dbInstance.getReadWeight()) ? 0 : Integer.parseInt(dbInstance.getReadWeight());
boolean usingDecrypt = !StringUtil.isEmpty(dbInstance.getUsingDecrypt()) && Boolean.parseBoolean(dbInstance.getUsingDecrypt());
List<Property> propertyList = dbInstance.getProperty();
PoolConfig poolConfig = null;
if (!propertyList.isEmpty()) {
Map<String, String> propertyMap = propertyList.stream().collect(Collectors.toMap(Property::getName, Property::getValue));
poolConfig = new PoolConfig();
ParameterMapping.mapping(poolConfig, propertyMap, null);
}
String password = dbInstance.getPassword();
boolean primary = (null == dbInstance.getPrimary() ? false : dbInstance.getPrimary());
if (primary) {
tmpDbInstanceConfig = new DbInstanceConfig(dbInstance.getName(), ip, port, url, dbInstance.getUser(), password, readWeight, dbInstance.getId(),
disabled, true, dbInstance.getMaxCon(), dbInstance.getMinCon(), poolConfig, usingDecrypt);
} else {
dbInstanceConfigList.add(new DbInstanceConfig(dbInstance.getName(), ip, port, url, dbInstance.getUser(), password, readWeight, dbInstance.getId(),
disabled, false, dbInstance.getMaxCon(), dbInstance.getMinCon(), poolConfig, usingDecrypt));
}
}
boolean disableHA = !StringUtil.isEmpty(dbGroup.getDisableHA()) && Boolean.parseBoolean(dbGroup.getDisableHA());
DbInstanceConfig[] dbInstanceConfigs = dbInstanceConfigList.isEmpty() ? new DbInstanceConfig[0] : dbInstanceConfigList.toArray(new DbInstanceConfig[0]);
DbGroupConfig dbGroupConf = new DbGroupConfig(dbGroup.getName(), tmpDbInstanceConfig, dbInstanceConfigs, dbGroup.getDelayThreshold(), disableHA);
//test connection
PhysicalDbInstance writeSource = new MySQLInstance(dbGroupConf.getWriteInstanceConfig(), dbGroupConf, true);
boolean isConnected = writeSource.testConnection();
if (!isConnected) {
throw new ConfigException("Can't connect to [" + dbGroupConf.getName() + "," + writeSource.getName() + "," + writeSource.getConfig().getUrl() + "]");
}
for (DbInstanceConfig readInstanceConfig : dbGroupConf.getReadInstanceConfigs()) {
MySQLInstance readInstance = new MySQLInstance(readInstanceConfig, dbGroupConf, false);
isConnected = readInstance.testConnection();
if (!isConnected) {
throw new ConfigException("Can't connect to [" + dbGroupConf.getName() + "," + readInstance.getName() + "," + readInstance.getConfig().getUrl() + "]");
}
}
}
} catch (IllegalAccessException | InvocationTargetException | IOException e) {
throw new ConfigException(e);
}
}
public static String getPasswordEncrypt(String instanceName, String name, String password) {
try {
return DecryptUtil.encrypt("1:" + instanceName + ":" + name + ":" + password);
@@ -3,14 +3,20 @@ package com.actiontech.dble.services.manager.information.tables;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.config.Fields;
import com.actiontech.dble.config.loader.xml.XMLUserLoader;
import com.actiontech.dble.config.model.user.*;
import com.actiontech.dble.config.model.user.ManagerUserConfig;
import com.actiontech.dble.config.model.user.RwSplitUserConfig;
import com.actiontech.dble.config.model.user.ShardingUserConfig;
import com.actiontech.dble.config.model.user.UserConfig;
import com.actiontech.dble.meta.ColumnMeta;
import com.actiontech.dble.services.manager.information.ManagerBaseTable;
import com.actiontech.dble.util.DecryptUtil;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import java.util.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
public class DbleEntry extends ManagerBaseTable {
@@ -77,7 +83,7 @@ public class DbleEntry extends ManagerBaseTable {
List<LinkedHashMap<String, String>> list = new ArrayList<>();
DbleServer.getInstance().getConfig().getUsers().entrySet().
stream().
sorted((a, b) -> Integer.valueOf(a.getValue().getId()).compareTo(b.getValue().getId())).
sorted((a, b) -> Integer.compare(a.getValue().getId(), b.getValue().getId())).
forEach(v -> {
UserConfig userConfig = v.getValue();
LinkedHashMap<String, String> map = Maps.newLinkedHashMap();
@@ -104,7 +110,7 @@ public class DbleEntry extends ManagerBaseTable {
map.put(COLUMN_CONN_ATTR_VALUE, null);
map.put(COLUMN_WHITE_IPS, getWhiteIps(userConfig.getWhiteIPs()));
map.put(COLUMN_READONLY, userConfig.isReadOnly() + "");
map.put(COLUMN_MAX_CONN_COUNT, userConfig.getMaxCon() == -1 ? "no limit" : userConfig.getMaxCon() + "");
map.put(COLUMN_MAX_CONN_COUNT, userConfig.getMaxCon() == 0 ? "no limit" : userConfig.getMaxCon() + "");
map.put(COLUMN_BLACKLIST, null);
}
@@ -118,7 +124,7 @@ public class DbleEntry extends ManagerBaseTable {
map.put(COLUMN_CONN_ATTR_VALUE, userConfig.getTenant());
map.put(COLUMN_WHITE_IPS, getWhiteIps(userConfig.getWhiteIPs()));
map.put(COLUMN_READONLY, userConfig.isReadOnly() + "");
map.put(COLUMN_MAX_CONN_COUNT, userConfig.getMaxCon() == -1 ? "no limit" : userConfig.getMaxCon() + "");
map.put(COLUMN_MAX_CONN_COUNT, userConfig.getMaxCon() == 0 ? "no limit" : userConfig.getMaxCon() + "");
map.put(COLUMN_BLACKLIST, userConfig.getBlacklist() == null ? null : userConfig.getBlacklist().getName());
}
@@ -132,7 +138,7 @@ public class DbleEntry extends ManagerBaseTable {
map.put(COLUMN_CONN_ATTR_VALUE, userConfig.getTenant());
map.put(COLUMN_WHITE_IPS, getWhiteIps(userConfig.getWhiteIPs()));
map.put(COLUMN_READONLY, "-");
map.put(COLUMN_MAX_CONN_COUNT, userConfig.getMaxCon() == -1 ? "no limit" : userConfig.getMaxCon() + "");
map.put(COLUMN_MAX_CONN_COUNT, userConfig.getMaxCon() == 0 ? "no limit" : userConfig.getMaxCon() + "");
map.put(COLUMN_BLACKLIST, userConfig.getBlacklist() == null ? null : userConfig.getBlacklist().getName());
}
@@ -3,20 +3,22 @@ package com.actiontech.dble.services.manager.information.tables;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.backend.datasource.PhysicalDbGroup;
import com.actiontech.dble.cluster.ClusterPathUtil;
import com.actiontech.dble.cluster.zkprocess.entity.Users;
import com.actiontech.dble.cluster.zkprocess.entity.user.RwSplitUser;
import com.actiontech.dble.cluster.zkprocess.parse.XmlProcessBase;
import com.actiontech.dble.config.ConfigFileName;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.config.Fields;
import com.actiontech.dble.config.loader.xml.XMLUserLoader;
import com.actiontech.dble.config.model.user.RwSplitUserConfig;
import com.actiontech.dble.config.model.user.UserConfig;
import com.actiontech.dble.config.util.ConfigException;
import com.actiontech.dble.meta.ColumnMeta;
import com.actiontech.dble.services.manager.information.ManagerWritableTable;
import com.actiontech.dble.util.IPAddressUtil;
import com.actiontech.dble.util.ResourceUtil;
import com.actiontech.dble.util.StringUtil;
import com.actiontech.dble.util.*;
import com.google.common.collect.Maps;
import javax.xml.bind.JAXBException;
import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.sql.SQLException;
import java.util.*;
@@ -37,6 +39,7 @@ public class DbleRwSplitEntry extends ManagerWritableTable {
private static final String COLUMN_MAX_CONN_COUNT = "max_conn_count";
private static final String COLUMN_BLACKLIST = "blacklist";
public static final String COLUMN_DB_GROUP = "db_group";
public static final String CONSTANT_NO_LIMIT = "no limit";
public DbleRwSplitEntry() {
super(TABLE_NAME, 10);
@@ -102,7 +105,7 @@ public class DbleRwSplitEntry extends ManagerWritableTable {
map.put(COLUMN_CONN_ATTR_KEY, rwSplitUserConfig.getTenant() != null ? "tenant" : null);
map.put(COLUMN_CONN_ATTR_VALUE, rwSplitUserConfig.getTenant());
map.put(COLUMN_WHITE_IPS, DbleEntry.getWhiteIps(rwSplitUserConfig.getWhiteIPs()));
map.put(COLUMN_MAX_CONN_COUNT, rwSplitUserConfig.getMaxCon() == -1 ? "no limit" : rwSplitUserConfig.getMaxCon() + "");
map.put(COLUMN_MAX_CONN_COUNT, rwSplitUserConfig.getMaxCon() == 0 ? CONSTANT_NO_LIMIT : rwSplitUserConfig.getMaxCon() + "");
map.put(COLUMN_BLACKLIST, rwSplitUserConfig.getBlacklist() == null ? null : rwSplitUserConfig.getBlacklist().getName());
map.put(COLUMN_DB_GROUP, dbGroupName);
list.add(map);
@@ -114,37 +117,167 @@ public class DbleRwSplitEntry extends ManagerWritableTable {
@Override
public int insertRows(List<LinkedHashMap<String, String>> rows) throws SQLException {
for (LinkedHashMap<String, String> row : rows) {
check(row);
}
//write to configuration
List<LinkedHashMap<String, String>> tempRowList = rows.stream().map(this::transformRow).collect(Collectors.toList());
XMLUserLoader xmlUserLoader = new XMLUserLoader();
xmlUserLoader.insertRwSplitUser(tempRowList, getXmlFilePath());
List<RwSplitUser> rwSplitUserList = rows.stream().map(this::transformRowToUser).collect(Collectors.toList());
Users users = getUser();
checkLogicalUniqueKeyDuplicate(users, rwSplitUserList);
users.getUser().addAll(rwSplitUserList);
saveUsers(users, getXmlFilePath());
return rows.size();
}
@Override
public int updateRows(Set<LinkedHashMap<String, String>> affectPks, LinkedHashMap<String, String> values) throws SQLException {
check(values);
//write to configuration
List<LinkedHashMap<String, String>> tempRowList = affectPks.stream().map(this::transformRow).collect(Collectors.toList());
XMLUserLoader xmlUserLoader = new XMLUserLoader();
xmlUserLoader.updateRwSplitUser(tempRowList, transformRow(values), getXmlFilePath());
affectPks.forEach(affectPk -> {
if (Boolean.FALSE.toString().equalsIgnoreCase(affectPk.get(COLUMN_ENCRYPT_CONFIGURED))) {
String password = DecryptUtil.decrypt(true, affectPk.get(COLUMN_USERNAME), affectPk.get(COLUMN_PASSWORD_ENCRYPT));
affectPk.put(COLUMN_PASSWORD_ENCRYPT, password);
}
affectPk.putAll(values);
});
List<RwSplitUser> rwSplitUserList = affectPks.stream().map(this::transformRowToUser).collect(Collectors.toList());
Users users = getUser();
updateList(users, rwSplitUserList, false);
saveUsers(users, getXmlFilePath());
return affectPks.size();
}
@Override
public int deleteRows(Set<LinkedHashMap<String, String>> affectPks) throws SQLException {
//write to configuration
List<LinkedHashMap<String, String>> tempRowList = affectPks.stream().map(this::transformRow).collect(Collectors.toList());
XMLUserLoader xmlUserLoader = new XMLUserLoader();
xmlUserLoader.deleteRwSplitUser(tempRowList, getXmlFilePath());
List<RwSplitUser> rwSplitUserList = affectPks.stream().map(this::transformRowToUser).collect(Collectors.toList());
Users users = getUser();
updateList(users, rwSplitUserList, true);
saveUsers(users, getXmlFilePath());
return affectPks.size();
}
private void check(LinkedHashMap<String, String> tempRowMap) throws SQLException {
private void saveUsers(Users users, String xmlFilePath) {
XmlProcessBase xmlProcess = new XmlProcessBase();
xmlProcess.addParseClass(Users.class);
try {
xmlProcess.initJaxbClass();
} catch (JAXBException e) {
throw new ConfigException(e);
}
xmlProcess.writeObjToXml(users, xmlFilePath, "user");
}
private Users getUser() {
XmlProcessBase xmlParseBase = new XmlProcessBase();
// xml file to bean
Users usersBean = null;
try {
xmlParseBase.addParseClass(Users.class);
xmlParseBase.initJaxbClass();
usersBean = (Users) xmlParseBase.baseParseXmlToBean(ConfigFileName.USER_XML);
} catch (JAXBException | XMLStreamException e) {
e.printStackTrace();
}
if (null == usersBean) {
throw new ConfigException("configuration is empty");
}
return usersBean;
}
private void updateList(Users users, List<RwSplitUser> rwSplitUserList, boolean isDelete) {
for (RwSplitUser rwSplitUser : rwSplitUserList) {
for (int i = 0; i < users.getUser().size(); i++) {
Object obj = users.getUser().get(i);
if (obj instanceof RwSplitUser) {
RwSplitUser sourceUser = (RwSplitUser) obj;
if (StringUtil.equals(sourceUser.getName(), rwSplitUser.getName()) && StringUtil.equals(sourceUser.getTenant(), rwSplitUser.getTenant())) {
if (!isDelete) {
users.getUser().set(i, rwSplitUser);
} else {
users.getUser().remove(i);
}
break;
}
}
}
}
}
private void checkLogicalUniqueKeyDuplicate(Users users, List<RwSplitUser> rwSplitUserList) throws SQLException {
List<RwSplitUser> sourceList = users.getUser().stream().filter(user -> user instanceof RwSplitUser).map(user -> (RwSplitUser) user).collect(Collectors.toList());
for (RwSplitUser rwSplitUser : rwSplitUserList) {
boolean isExist = sourceList.stream().anyMatch(sourceUser -> StringUtil.equals(sourceUser.getName(), rwSplitUser.getName()) && StringUtil.equals(sourceUser.getTenant(), rwSplitUser.getTenant()));
if (isExist) {
String msg = String.format("Duplicate entry '%s-%s-%s'for logical unique '%s-%s-%s'", rwSplitUser.getName(),
StringUtil.isEmpty(rwSplitUser.getTenant()) ? null : "tenant", rwSplitUser.getTenant(), COLUMN_USERNAME, COLUMN_CONN_ATTR_KEY, COLUMN_CONN_ATTR_VALUE);
throw new SQLException(msg, "42S22", ErrorCode.ER_DUP_ENTRY);
}
}
}
private void checkBooleanVal(LinkedHashMap<String, String> tempRowMap) {
if (tempRowMap.containsKey(COLUMN_ENCRYPT_CONFIGURED) && !StringUtil.isEmpty(tempRowMap.get(COLUMN_ENCRYPT_CONFIGURED))) {
String encryptConfigured = tempRowMap.get(COLUMN_ENCRYPT_CONFIGURED);
if (!StringUtil.equalsIgnoreCase(encryptConfigured, Boolean.FALSE.toString()) && !StringUtil.equalsIgnoreCase(encryptConfigured, Boolean.TRUE.toString())) {
throw new ConfigException("Column 'encrypt_configured' values only support 'false' or 'true'.");
}
}
if (!StringUtil.isBlank(tempRowMap.get(COLUMN_CONN_ATTR_KEY))) {
if (!StringUtil.equals(tempRowMap.get(COLUMN_CONN_ATTR_KEY), "tenant")) {
throw new ConfigException("'conn_attr_key' value is ['tenant',null].");
}
if (StringUtil.isBlank(tempRowMap.get(COLUMN_CONN_ATTR_VALUE))) {
throw new ConfigException("'conn_attr_key' and 'conn_attr_value' are used together.");
}
} else {
if (!StringUtil.isBlank(tempRowMap.get(COLUMN_CONN_ATTR_VALUE))) {
throw new ConfigException("'conn_attr_key' and 'conn_attr_value' are used together.");
}
}
}
private RwSplitUser transformRowToUser(LinkedHashMap<String, String> map) {
if (null == map || map.isEmpty()) {
return null;
}
check(map);
RwSplitUser rwSplitUser = new RwSplitUser();
for (Map.Entry<String, String> entry : map.entrySet()) {
switch (entry.getKey()) {
case COLUMN_USERNAME:
rwSplitUser.setName(entry.getValue());
break;
case COLUMN_PASSWORD_ENCRYPT:
rwSplitUser.setPassword(entry.getValue());
break;
case COLUMN_ENCRYPT_CONFIGURED:
rwSplitUser.setUsingDecrypt(entry.getValue());
break;
case COLUMN_CONN_ATTR_VALUE:
rwSplitUser.setTenant(entry.getValue());
break;
case COLUMN_WHITE_IPS:
rwSplitUser.setWhiteIPs(entry.getValue());
break;
case COLUMN_MAX_CONN_COUNT:
if (!StringUtil.isBlank(entry.getValue())) {
rwSplitUser.setMaxCon(IntegerUtil.parseInt(entry.getValue().replace(CONSTANT_NO_LIMIT, "0")));
}
if (rwSplitUser.getMaxCon() < 0) {
throw new ConfigException("Column 'max_conn_count' value cannot be less than 0.");
}
break;
case COLUMN_DB_GROUP:
rwSplitUser.setDbGroup(entry.getValue());
break;
default:
break;
}
}
return rwSplitUser;
}
private void check(LinkedHashMap<String, String> tempRowMap) {
//check whiteIPs
checkWhiteIPs(tempRowMap);
//check db_group
@@ -153,11 +286,12 @@ public class DbleRwSplitEntry extends ManagerWritableTable {
checkBooleanVal(tempRowMap);
}
private void checkBooleanVal(LinkedHashMap<String, String> tempRowMap) {
if (tempRowMap.containsKey(COLUMN_ENCRYPT_CONFIGURED) && !StringUtil.isEmpty(tempRowMap.get(COLUMN_ENCRYPT_CONFIGURED))) {
String encryptConfigured = tempRowMap.get(COLUMN_ENCRYPT_CONFIGURED);
if (!StringUtil.equalsIgnoreCase(encryptConfigured, Boolean.FALSE.toString()) && !StringUtil.equalsIgnoreCase(encryptConfigured, Boolean.TRUE.toString())) {
throw new ConfigException("Column 'encrypt_configured' values only support 'false' or 'true'.");
private void checkDbGroup(LinkedHashMap<String, String> tempRowMap) {
if (tempRowMap.containsKey(COLUMN_DB_GROUP)) {
Map<String, PhysicalDbGroup> dbGroupMap = DbleServer.getInstance().getConfig().getDbGroups();
boolean isExist = dbGroupMap.keySet().stream().anyMatch(groupName -> StringUtil.equals(groupName, tempRowMap.get(COLUMN_DB_GROUP)));
if (!isExist) {
throw new ConfigException("Column 'db_group' value '" + tempRowMap.get(COLUMN_DB_GROUP) + "' does not exist or not active.");
}
}
}
@@ -168,43 +302,4 @@ public class DbleRwSplitEntry extends ManagerWritableTable {
IPAddressUtil.checkWhiteIPs(tempRowMap.get(COLUMN_WHITE_IPS));
}
}
private void checkDbGroup(LinkedHashMap<String, String> tempRowMap) throws SQLException {
if (tempRowMap.containsKey(COLUMN_DB_GROUP)) {
Map<String, PhysicalDbGroup> dbGroupMap = DbleServer.getInstance().getConfig().getDbGroups();
boolean isExist = dbGroupMap.keySet().stream().anyMatch(groupName -> StringUtil.equals(groupName, tempRowMap.get(COLUMN_DB_GROUP)));
if (!isExist) {
throw new SQLException("Column 'db_group' value '" + tempRowMap.get(COLUMN_DB_GROUP) + "' does not exist or not active.", "42S22", ErrorCode.ER_ERROR_ON_WRITE);
}
}
}
private LinkedHashMap<String, String> transformRow(LinkedHashMap<String, String> map) {
if (null == map || map.isEmpty()) {
return null;
}
LinkedHashMap<String, String> xmlMap = Maps.newLinkedHashMap();
if (null != map.get(COLUMN_USERNAME)) {
xmlMap.put("name", map.get(COLUMN_USERNAME));
}
if (null != map.get(COLUMN_PASSWORD_ENCRYPT)) {
xmlMap.put("password", map.get(COLUMN_PASSWORD_ENCRYPT));
}
if (null != map.get(COLUMN_WHITE_IPS)) {
xmlMap.put("whiteIPs", map.get(COLUMN_WHITE_IPS));
}
if (null != map.get(COLUMN_MAX_CONN_COUNT)) {
xmlMap.put("maxCon", map.get(COLUMN_MAX_CONN_COUNT));
}
if (null != map.get(COLUMN_CONN_ATTR_VALUE)) {
xmlMap.put("tenant", map.get(COLUMN_CONN_ATTR_VALUE));
}
if (null != map.get(COLUMN_DB_GROUP)) {
xmlMap.put("dbGroup", map.get(COLUMN_DB_GROUP));
}
if (null != map.get(COLUMN_ENCRYPT_CONFIGURED)) {
xmlMap.put("usingDecrypt", map.get(COLUMN_ENCRYPT_CONFIGURED));
}
return xmlMap;
}
}
@@ -84,14 +84,14 @@ public final class ShowUser {
row.add(StringUtil.encode("N", charset));
row.add(StringUtil.encode(shardingUser.isReadOnly() ? "Y" : "N", charset));
int maxCon = shardingUser.getMaxCon();
row.add(StringUtil.encode(maxCon == -1 ? "no limit" : maxCon + "", charset));
row.add(StringUtil.encode(maxCon == 0 ? "no limit" : maxCon + "", charset));
} else if (user instanceof ManagerUserConfig) {
ManagerUserConfig mUser = (ManagerUserConfig) user;
row.add(StringUtil.encode(user.getName(), charset));
row.add(StringUtil.encode("Y", charset));
row.add(StringUtil.encode(mUser.isReadOnly() ? "Y" : "N", charset));
int maxCon = mUser.getMaxCon();
row.add(StringUtil.encode(maxCon == -1 ? "no limit" : maxCon + "", charset));
row.add(StringUtil.encode(maxCon == 0 ? "no limit" : maxCon + "", charset));
} else {
RwSplitUserConfig rUser = (RwSplitUserConfig) user;
if (rUser.getTenant() != null) {
@@ -5,6 +5,8 @@
*/
package com.actiontech.dble.util;
import com.actiontech.dble.config.util.ConfigException;
/**
* @author mycat
*/
@@ -81,4 +83,14 @@ public final class IntegerUtil {
}
}
public static int parseInt(String intStr) {
try {
if (!StringUtil.isBlank(intStr)) {
return Integer.parseInt(intStr);
}
} catch (NumberFormatException e) {
throw new ConfigException("incorrect integer value: '" + intStr + "'");
}
throw new ConfigException("incorrect integer value: 'null'");
}
}
@@ -5,6 +5,8 @@
*/
package com.actiontech.dble.util;
import com.actiontech.dble.config.util.ConfigException;
/**
* @author mycat
*/
@@ -84,4 +86,26 @@ public final class LongUtil {
}
}
public static boolean isLong(String intStr) {
try {
if (!StringUtil.isBlank(intStr)) {
Long.parseLong(intStr);
return true;
}
} catch (NumberFormatException e) {
return false;
}
return false;
}
public static long parseLong(String intStr) {
try {
if (!StringUtil.isBlank(intStr)) {
return Long.parseLong(intStr);
}
} catch (NumberFormatException e) {
throw new ConfigException("incorrect long value: '" + intStr + "'");
}
throw new ConfigException("incorrect long value: 'null'");
}
}
@@ -97,6 +97,10 @@ public final class StringUtil {
return ((str == null) || (str.length() == 0));
}
public static boolean isBlank(String str) {
return ((str == null) || (str.length() == 0)) || (str.trim().length() == 0);
}
public static byte[] hexString2Bytes(char[] hexString, int offset,
int length) {
if (hexString == null) {