mirror of
https://github.com/actiontech/dble.git
synced 2026-05-05 14:01:15 -05:00
Merge pull request #3767 from actiontech/fix/test-2010
fix[inner-2290]:merge dble_information related pr
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
+9
-2
@@ -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;
|
||||
}
|
||||
|
||||
+14
-7
@@ -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() {
|
||||
}
|
||||
}
|
||||
|
||||
+121
-36
@@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+157
-259
@@ -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);
|
||||
|
||||
+12
-6
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
+161
-66
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user