getSetList(){
118 | return this.setList;
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/output/RowModifyTypeEnum.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.output;
2 |
3 | /**
4 | * row data 事件类型
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public enum RowModifyTypeEnum {
10 | INSERT,UPDATE,DELETE;
11 | }
12 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/AbstractRequest.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
4 | import com.hiriver.unbiz.mysql.lib.protocol.tool.SafeByteArrayOutputStream;
5 |
6 | /**
7 | * mysql request的抽象实现
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public abstract class AbstractRequest implements Request {
13 | private int sequenceId;
14 |
15 | public int getSequenceId() {
16 | return sequenceId;
17 | }
18 |
19 | public void setSequenceId(int sequenceId) {
20 | this.sequenceId = sequenceId;
21 | }
22 |
23 | @Override
24 | public byte[] toByteArray() {
25 | SafeByteArrayOutputStream out = new SafeByteArrayOutputStream(256);
26 | // packet header holder
27 | out.safeWrite(MysqlNumberUtils.write4Int(0));
28 | fillPayload(out);
29 | byte[] buffer = out.toByteArray();
30 | PacketHeader header = new PacketHeader();
31 | header.setPayloadLen(buffer.length - 4);
32 | header.setSequenceId(sequenceId);
33 |
34 | System.arraycopy(header.toByteArray(), 0, buffer, 0, 4);
35 | return buffer;
36 | }
37 |
38 | /**
39 | * 填充请求主体对象
40 | *
41 | * @param out 输出的byte[] 流
42 | */
43 | protected abstract void fillPayload(SafeByteArrayOutputStream out);
44 | }
45 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/AbstractResponse.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | /**
4 | * 抽象的mysql client-server协议的返回包
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public abstract class AbstractResponse implements Response {
10 | private boolean checkSum = false;
11 | public boolean isCheckSum() {
12 | return checkSum;
13 | }
14 | public void setCheckSum(boolean checkSum) {
15 | this.checkSum = checkSum;
16 | }
17 | @Override
18 | public void parse(byte[] buf, Position pos) {
19 | throw new RuntimeException("don't support this method.");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/CapabilityFlagConst.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | /**
4 | * 描述与mysql交互时客户端或mysql服务端需要具备的能力。
5 | *
6 | * 参见
7 | * http://dev.
8 | * mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags
9 | *
10 | * @author hexiufeng
11 | *
12 | */
13 | public interface CapabilityFlagConst {
14 | int CLIENT_LONG_PASSWORD = 0x00000001;
15 | int CLIENT_PLUGIN_AUTH = 0x00080000;
16 | int CLIENT_SECURE_CONNECTION = 0x00008000;
17 | int CLIENT_PROTOCOL_41 = 0x00000200;
18 | int CLIENT_CONNECT_WITH_DB = 0x00000008;
19 | int CLIENT_CONNECT_ATTRS = 0x00100000;
20 | int CLIENT_TRANSACTIONS = 0x00002000;
21 | int CLIENT_LONG_FLAG = 0x00000004;
22 | int CLIENT_MULTI_RESULTS = 0x00020000;
23 | int CLIENT_FOUND_ROWS = 0x00000002;
24 | int CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = 0x00200000;
25 | int CLIENT_LOCAL_FILES = 0x00000080;
26 | int CLIENT_INTERACTIVE = 0x00000400;
27 | int CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS = 0x00400000;
28 | }
29 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/ColumnFlagConst.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | /**
4 | * 字段的定义信息,copy from mysql c 源码
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public interface ColumnFlagConst {
10 | int NOT_NULL_FLAG = 0x01; /* Field can't be NULL */
11 | int PRI_KEY_FLAG = 0x02; /* Field is part of a primary key */
12 | int UNIQUE_KEY_FLAG = 0x04; /* Field is part of a unique key */
13 | int MULTIPLE_KEY_FLAG = 0x08; /* Field is part of a key */
14 | int BLOB_FLAG = 0x10; /* Field is a blob */
15 | int UNSIGNED_FLAG = 0x20; /* Field is unsigned */
16 | int ZEROFILL_FLAG = 0x40; /* Field is zerofill */
17 | int BINARY_FLAG = 0x80; /* Field is binary */
18 | int ENUM_FLAG = 0x0100; /* field is an enum */
19 | int AUTO_INCREMENT_FLAG = 0x0200; /* field is a autoincrement field */
20 | int TIMESTAMP_FLAG = 0x0400; /* Field is a timestamp */
21 | int SET_FLAG = 0x0800; /* field is a set */
22 | int NO_DEFAULT_VALUE_FLAG = 0x1000; /* Field doesn't have default value */
23 | int ON_UPDATE_NOW_FLAG = 0x2000; /* Field is set to NOW on UPDATE */
24 | int NUM_FLAG = 0x8000; /* Field is num (for clients) */
25 | }
26 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/EOFPacket.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
4 |
5 | /**
6 | * 响应结束包。用于一个请求可能返回大量数据时,比执行一个sql查询.
7 | *
8 | * see
9 | * http://dev.mysql.com/doc/internals/en/packet
10 | * -EOF_Packet.html
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class EOFPacket extends AbstractResponse implements Response {
16 | /**
17 | * MUST be 0xfe
18 | */
19 | private int header;
20 | private int warnings;
21 | private int statusFlags;
22 |
23 | @Override
24 | public void parse(byte[] buf) {
25 | Position pos = Position.factory();
26 | header = MysqlNumberUtils.read1Int(buf, pos);
27 | warnings = MysqlNumberUtils.read2Int(buf, pos);
28 | statusFlags = MysqlNumberUtils.read2Int(buf, pos);
29 | }
30 |
31 | public int getHeader() {
32 | return header;
33 | }
34 |
35 | public int getWarnings() {
36 | return warnings;
37 | }
38 |
39 | public int getStatusFlags() {
40 | return statusFlags;
41 | }
42 |
43 | public void setHeader(int header) {
44 | this.header = header;
45 | }
46 |
47 | public void setWarnings(int warnings) {
48 | this.warnings = warnings;
49 | }
50 |
51 | public void setStatusFlags(int statusFlags) {
52 | this.statusFlags = statusFlags;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/ERRPacket.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | import java.io.UnsupportedEncodingException;
4 |
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
7 |
8 | /**
9 | * 错误数据包。
10 | *
11 | * see
12 | * http://dev.mysql.com/doc/internals/en/packet
13 | * -ERR_Packet.html
14 | *
15 | * @author hexiufeng
16 | *
17 | */
18 | public class ERRPacket extends AbstractResponse implements Response {
19 | /**
20 | * MUST be 0xff
21 | */
22 | private int header;
23 | private int errorCode;
24 | private int sqlStateMarker;
25 | private byte[] sqlState;
26 | private String errorMessage;
27 |
28 | @Override
29 | public void parse(byte[] buf) {
30 | Position pos = Position.factory();
31 | header = MysqlNumberUtils.read1Int(buf, pos);
32 | errorCode = MysqlNumberUtils.read2Int(buf, pos);
33 | // sqlStateMarker = MysqlNumberUtils.read1Int(buf, pos);
34 | // sqlState = MysqlStringUtils.readFixString(buf, pos, 3);
35 | try {
36 | errorMessage = new String(MysqlStringUtils.readEofString(buf, pos, super.isCheckSum()), "utf-8");
37 | } catch (UnsupportedEncodingException e) {
38 | // ignore
39 | }
40 | }
41 |
42 | public int getHeader() {
43 | return header;
44 | }
45 |
46 | public int getErrorCode() {
47 | return errorCode;
48 | }
49 |
50 | public int getSqlStateMarker() {
51 | return sqlStateMarker;
52 | }
53 |
54 | public byte[] getSqlState() {
55 | return sqlState;
56 | }
57 |
58 | public String getErrorMessage() {
59 | return errorMessage;
60 | }
61 |
62 | public void setErrorCode(int errorCode) {
63 | this.errorCode = errorCode;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/OKPacket.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
4 |
5 | /**
6 | * 正确响应数据包。
7 | *
8 | * see
9 | * http://dev.mysql.com/doc/internals/en/packet-
10 | * OK_Packet.html
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class OKPacket extends AbstractResponse implements Response {
16 | /**
17 | * MUST be 0x00
18 | */
19 | private int header;
20 | private long affectedRows;
21 | private long lastInsertId;
22 | private int statusFlags;
23 | private int warnings;
24 |
25 | @Override
26 | public void parse(byte[] buf) {
27 | Position pos = Position.factory();
28 | header = MysqlNumberUtils.read1Int(buf, pos);
29 | affectedRows = MysqlNumberUtils.readLencodeLong(buf, pos);
30 | lastInsertId = MysqlNumberUtils.readLencodeLong(buf, pos);
31 | statusFlags = MysqlNumberUtils.read2Int(buf, pos);
32 | warnings = MysqlNumberUtils.read2Int(buf, pos);
33 | }
34 |
35 | public int getHeader() {
36 | return header;
37 | }
38 |
39 | public long getAffectedRows() {
40 | return affectedRows;
41 | }
42 |
43 | public long getLastInsertId() {
44 | return lastInsertId;
45 | }
46 |
47 | public int getStatusFlags() {
48 | return statusFlags;
49 | }
50 |
51 | public int getWarnings() {
52 | return warnings;
53 | }
54 |
55 | public void setHeader(int header) {
56 | this.header = header;
57 | }
58 |
59 | public void setAffectedRows(long affectedRows) {
60 | this.affectedRows = affectedRows;
61 | }
62 |
63 | public void setLastInsertId(long lastInsertId) {
64 | this.lastInsertId = lastInsertId;
65 | }
66 |
67 | public void setStatusFlags(int statusFlags) {
68 | this.statusFlags = statusFlags;
69 | }
70 |
71 | public void setWarnings(int warnings) {
72 | this.warnings = warnings;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/PacketHeader.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
4 |
5 | /**
6 | * 与mysql进行交互的数据包的头,msyql的由固定4个字节组成:
7 | *
8 | * - 前三个字节是payloadLen
9 | * - 最后一个字节是sequenceId
10 | *
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class PacketHeader extends AbstractResponse implements Response, Request {
16 | /**
17 | * 后续数据的字节数
18 | */
19 | private int payloadLen;
20 | /**
21 | * 数据包的序号,从0开始,下一名开始时重置为0
22 | */
23 | private int sequenceId;
24 |
25 | public int getPayloadLen() {
26 | return payloadLen;
27 | }
28 |
29 | public void setPayloadLen(int payloadLen) {
30 | this.payloadLen = payloadLen;
31 | }
32 |
33 | public int getSequenceId() {
34 | return sequenceId;
35 | }
36 |
37 | public void setSequenceId(int sequenceId) {
38 | this.sequenceId = sequenceId;
39 | }
40 |
41 | @Override
42 | public void parse(byte[] packetHeader) {
43 | Position pos = Position.factory();
44 | payloadLen = MysqlNumberUtils.read3Int(packetHeader, pos);
45 | sequenceId = MysqlNumberUtils.read1Int(packetHeader, pos);
46 | }
47 |
48 | @Override
49 | public byte[] toByteArray() {
50 | byte[] buffer = MysqlNumberUtils.write4Int(payloadLen);
51 | buffer[3] = (byte) sequenceId;
52 | return buffer;
53 | }
54 |
55 | /**
56 | * header的字节数
57 | *
58 | * @return header的字节数
59 | */
60 | public int getExpectLen() {
61 | return 4;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/Position.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | /**
4 | * 从byte数组中解析数据时,描述当前解析到哪个字节的辅助类,
5 | * 在一包数据被持续解析时非常有用,比如解析多行数据时,
6 | *
7 | * @author hexiufeng
8 | *
9 | */
10 | public final class Position {
11 | private int pos;
12 |
13 | private Position(int pos) {
14 | this.pos = pos;
15 | }
16 |
17 | public static Position factory() {
18 | return factory(0);
19 | }
20 |
21 | public static Position factory(int pos) {
22 | return new Position(pos);
23 | }
24 |
25 | public int getPos() {
26 | return this.pos;
27 | }
28 |
29 | public int getAndForwordPos() {
30 | return pos++;
31 | }
32 |
33 | public int getAndForwordPos(int step) {
34 | int cur = pos;
35 | pos += step;
36 | return cur;
37 | }
38 |
39 | public int forwardPos() {
40 | return ++pos;
41 | }
42 |
43 | public int forwardPos(int step) {
44 | pos += step;
45 | return pos;
46 | }
47 |
48 | public void reset() {
49 | pos = 0;
50 | }
51 |
52 | public void reset(int newPos) {
53 | pos = newPos;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/Request.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | /**
4 | * 与mysql交互的请求.该请求对象包含请求头和请求主体数据
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public interface Request {
10 | /**
11 | * 把请求对象转换为可以socket发送的byte数组
12 | *
13 | * @return byte[]数组
14 | */
15 | byte[] toByteArray();
16 | }
17 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/Response.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol;
2 |
3 | /**
4 | * 与mysql交互的响应对象
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public interface Response {
10 | /**
11 | * 把byte[]数据转换为响应对象
12 | *
13 | * @param buf byte[]数组
14 | */
15 | void parse(byte[] buf);
16 |
17 | /**
18 | * 解析当前buf的数据,使用pos来控制当已经处理数据的位置,在数据被多次处理时非常
19 | * 有效,比如在解析多行数据时
20 | *
21 | * @param buf 已经从mysql server读取到数据缓存
22 | * @param pos 保存当前已经处理的位置
23 | */
24 | void parse(byte[] buf, Position pos);
25 | }
26 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/BitColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
7 |
8 | /**
9 | * bit类型的数据解析器
10 | *
11 | * @author hexiufeng
12 | *
13 | */
14 | public class BitColumnTypeValueParser implements ColumnTypeValueParser {
15 |
16 | @Override
17 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
18 | int nbits = ((meta >>> 8) * 8) + (meta & 0xff);
19 | int len = (nbits + 7) / 8;
20 | byte[] bitBuff = MysqlStringUtils.readFixString(buf, pos, len);
21 | StringBuilder sb = new StringBuilder();
22 | for(int i = 0; i < bitBuff.length;i++){
23 | int v = bitBuff[i] & 0xff;
24 | if(i == 0) {
25 | sb.append(Integer.toBinaryString(v));
26 | continue;
27 | }
28 | String pad = "00000000" + Integer.toBinaryString(v);
29 | sb.append(pad.substring(pad.length() - 8));
30 | }
31 | return "0b" + sb.toString();
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/BlobColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.CharsetMapping;
4 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
5 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
7 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
8 | import com.hiriver.unbiz.mysql.lib.protocol.tool.StringTool;
9 |
10 | /**
11 | * blob or text,text和 blob在底层存储是相同的,只是blob类型的字符集是binary,而text类型有utf-8或者其他字符集
12 | *
13 | * @author hexiufeng
14 | *
15 | */
16 | public class BlobColumnTypeValueParser implements ColumnTypeValueParser {
17 |
18 | @Override
19 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
20 | int len = (int) MysqlNumberUtils.readNInt(buf, pos, meta);
21 | if (CharsetMapping.isBinary(columnDef.getCharset())) {
22 | return MysqlStringUtils.readFixString(buf, pos, len);
23 | } else {
24 | return StringTool.safeConvertBytes2String(MysqlStringUtils.readFixString(buf, pos, len),
25 | columnDef.getCharset());
26 | }
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/ColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 |
6 | /**
7 | * binlog数据解析器,根据不同的列数据类型不同,而有不同解析方式
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public interface ColumnTypeValueParser {
13 | /**
14 | * 根据binlog日志数据解析出对应的java类型数据。
15 | *
16 | * @param buf 二进制的binlog数据
17 | * @param pos 用于记录buffer中已解析数据的位置
18 | * @param columnDef 列的类型
19 | * @param meta binlog中的该类型的meta信息
20 | * @return java数据类型
21 | */
22 | Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta);
23 | }
24 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/DateColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import java.util.Calendar;
4 |
5 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
6 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
7 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
8 |
9 | /**
10 | * date 类型的解析器
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class DateColumnTypeValueParser implements ColumnTypeValueParser {
16 |
17 | @Override
18 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
19 | int tmp = MysqlNumberUtils.read3Int(buf, pos);
20 | int day = tmp & 31;
21 | int month = (tmp >> 5 & 15);
22 | int year = tmp >> 9;
23 | Calendar cal = Calendar.getInstance();
24 | cal.set(year, month - 1, day, 0, 0, 0);
25 | return cal.getTime();
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/DateTime2ColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import java.util.Calendar;
4 |
5 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
6 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
7 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
8 |
9 | /**
10 | * datetime2 类型的解析器。处理逻辑来自mysql源码
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class DateTime2ColumnTypeValueParser implements ColumnTypeValueParser {
16 | private static final long DATETIMEF_INT_OFS = 0x8000000000L;
17 |
18 | @Override
19 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
20 | long val = myDatetimePackedFromBinary(buf, pos, meta);
21 | // int secondPart = (int)(val % (1L<<24));
22 | long ymdhms = val >>> 24;
23 | long ymd = ymdhms >>> 17;
24 | long ym = ymd >> 5;
25 | long hms = ymdhms % (1L << 17);
26 |
27 | int day = (int) (ymd % (1 << 5));
28 | int month = (int) (ym % 13);
29 | int year = (int) (ym / 13);
30 |
31 | int second = (int) (hms % (1 << 6));
32 | int minute = (int) ((hms >> 6) % (1 << 6));
33 | int hour = (int) (hms >> 12);
34 |
35 | Calendar cal = Calendar.getInstance();
36 |
37 | cal.set(year, month - 1, day, hour, minute, second);
38 | cal.set(Calendar.MILLISECOND, 0);
39 | return cal.getTime();
40 | }
41 |
42 | private long myDatetimePackedFromBinary(byte[] buf, Position pos, int dec) {
43 | long intpart = MysqlNumberUtils.readBigEdianNInt(buf, pos, 5) - DATETIMEF_INT_OFS;
44 | long frac = 0;
45 | switch (dec) {
46 | case 0:
47 | default:
48 | return intpart << 24;
49 | case 1:
50 | case 2:
51 | frac = MysqlNumberUtils.read1Int(buf, pos) * 10000;
52 | break;
53 | case 3:
54 | case 4:
55 | frac = (MysqlNumberUtils.readBigEdianNInt(buf, pos, 2) * 100);
56 | break;
57 | case 5:
58 | case 6:
59 | frac = (MysqlNumberUtils.readBigEdianNInt(buf, pos, 3));
60 | break;
61 | }
62 | return intpart << 24 + frac;
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/DateTimeColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import java.util.Calendar;
4 |
5 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
6 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
7 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
8 |
9 | /**
10 | * datetime 类型解析器
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class DateTimeColumnTypeValueParser implements ColumnTypeValueParser {
16 |
17 | @Override
18 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
19 | long tmp = MysqlNumberUtils.read8Int(buf, pos);
20 | long d = tmp / 1000000;
21 | long t = tmp % 1000000;
22 |
23 | int year = (int) (d / 10000);
24 | int month = (int) ((d % 10000) / 100);
25 | int date = (int) (d % 100);
26 |
27 | int hour = (int) (t / 10000);
28 | int minute = (int) ((t % 10000) / 100);
29 | int second = (int) (t % 100);
30 | Calendar cal = Calendar.getInstance();
31 | cal.set(year, month - 1, date, hour, minute, second);
32 | cal.set(Calendar.MILLISECOND, 0);
33 | return cal.getTime();
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/DecimalColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
7 | import com.hiriver.unbiz.mysql.lib.protocol.tool.MysqlDecimal;
8 |
9 | import java.math.BigDecimal;
10 |
11 | /**
12 | * decimal 数据类型解析器
13 | *
14 | *
15 | * @author hexiufeng
16 | *
17 | */
18 | public class DecimalColumnTypeValueParser implements ColumnTypeValueParser {
19 |
20 | @Override
21 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
22 | int scale = (meta >>> 8);
23 | int precision = meta & 0xff;
24 | MysqlDecimal myDecimal = new MysqlDecimal(precision,scale);
25 | byte[] decBuf = MysqlStringUtils.readFixString(buf, pos, myDecimal.getBinSize());
26 | myDecimal.parse(decBuf);
27 | return myDecimal.toDecimal();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/DoubleColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.nio.ByteOrder;
5 |
6 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
7 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
8 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
9 |
10 | /**
11 | * double数据类型解析器
12 | *
13 | * @author hexiufeng
14 | *
15 | */
16 | public class DoubleColumnTypeValueParser implements ColumnTypeValueParser {
17 |
18 | @Override
19 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
20 | byte[] array = MysqlStringUtils.readFixString(buf, pos, 8);
21 | ByteBuffer bbf = ByteBuffer.wrap(array);
22 | bbf.order(ByteOrder.LITTLE_ENDIAN);
23 | return bbf.getDouble();
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/EnumColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 |
7 | /**
8 | * mysql枚举数据类型解析器,mysql枚举在mysql binlog内部本质上是string类型。代码逻辑来自mysql源码
9 | *
10 | * mysql的枚举在底层上只存储枚举对应的索引值,而每个索引所代表的文本值存储在表结构的元数据中,每次的
11 | * 查询结果返回时做一次索引到文本的转化,这样可以降低存储空间
12 | *
13 | * 注意:枚举的值是从1开始的。
14 | *
15 | * @author hexiufeng
16 | *
17 | */
18 | public class EnumColumnTypeValueParser implements ColumnTypeValueParser {
19 |
20 | @Override
21 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
22 | int value = 0;
23 | int flag = meta & 0xff;
24 | switch (flag) {
25 | case 1:
26 | value = MysqlNumberUtils.read1Int(buf, pos);
27 | break;
28 | case 2:
29 | value = (int) MysqlNumberUtils.readBigEdianNInt(buf, pos, 2);
30 | break;
31 | default:
32 | }
33 | return columnDef.getEnumList().get(value - 1);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/FloatColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.nio.ByteOrder;
5 |
6 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
7 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
8 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
9 |
10 | /**
11 | * float数据类型解析器
12 | *
13 | * @author hexiufeng
14 | *
15 | */
16 | public class FloatColumnTypeValueParser implements ColumnTypeValueParser {
17 |
18 | @Override
19 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
20 | byte[] array = MysqlStringUtils.readFixString(buf, pos, 4);
21 | ByteBuffer bbf = ByteBuffer.wrap(array);
22 | bbf.order(ByteOrder.LITTLE_ENDIAN);
23 | return bbf.getFloat();
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/IntegerColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 |
7 | /**
8 | * 32 bit int类型解析器,对应mysql的long,mysql的长整形是bigint,如果该字段是usigned的,返回的是java Long类型
9 | *
10 | * @author hexiufeng
11 | *
12 | */
13 | public class IntegerColumnTypeValueParser implements ColumnTypeValueParser {
14 | private final int len;
15 |
16 | public IntegerColumnTypeValueParser(int len) {
17 | this.len = len;
18 | }
19 |
20 | @Override
21 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
22 | if (columnDef.isUnsigned()) {
23 | long value = MysqlNumberUtils.readNInt(buf, pos, len);
24 | if (isShort() || isByte()) {
25 | return (int) value;
26 | }
27 | return Long.valueOf(value);
28 | } else {
29 | int value = MysqlNumberUtils.readNRawInt(buf, pos, len);
30 | if(isShort()){
31 | return Integer.valueOf((short)value);
32 | }
33 | if(isByte()){
34 | return Integer.valueOf((byte)value);
35 | }
36 | return Integer.valueOf(value);
37 | }
38 | }
39 |
40 | private boolean isShort() {
41 | return len == 2;
42 | }
43 | private boolean isByte() {
44 | return len == 1;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/LongColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import java.math.BigInteger;
4 | import java.nio.ByteBuffer;
5 | import java.nio.ByteOrder;
6 |
7 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
8 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
9 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
10 |
11 | /**
12 | * mysql bigint类型的解析器,如果该字段是unsigned,返回的是BigInteger
13 | *
14 | *
15 | * @author hexiufeng
16 | *
17 | */
18 | public class LongColumnTypeValueParser implements ColumnTypeValueParser {
19 |
20 | @Override
21 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
22 | long value = MysqlNumberUtils.read8Int(buf, pos);
23 | if (columnDef.isUnsigned()) {
24 | ByteBuffer bbf = ByteBuffer.allocate(8);
25 | bbf.order(ByteOrder.BIG_ENDIAN);
26 | bbf.putLong(value);
27 | return new BigInteger(bbf.array());
28 | } else {
29 | return Long.valueOf(value);
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/NullColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 |
6 | /**
7 | * null类型的数据解析器,一般没用
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public class NullColumnTypeValueParser implements ColumnTypeValueParser {
13 |
14 | @Override
15 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
16 | return null;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/SetColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
6 |
7 | /**
8 | * mysql set类型的解析器,它和枚举一样,本质上是string,一般不用
9 | *
10 | * mysql的set与枚举类似,也是在表结构的元数据中定义一组文本值,在数据存储内部值存文本的索引,
11 | * 从而降低存储空间,但与枚举不同的是一个set值可能存储多个值,比如 set定义为(a,b,c,d),但
12 | * 某条记录只存储(a,d),在mysql是使用位图索引实现的,set中每个元素索引使用位的位置代替,比如
13 | * set(a,b,c,d)对应1111,那么(a,d)就是1001
14 | *
15 | *
16 | *
17 | * @author hexiufeng
18 | *
19 | */
20 | public class SetColumnTypeValueParser implements ColumnTypeValueParser {
21 |
22 | private static final int[] ONES = {
23 | 1,
24 | 1 << 1,
25 | 1 << 2,
26 | 1 << 3,
27 | 1 << 4,
28 | 1 << 5,
29 | 1 << 6,
30 | 1 << 7
31 |
32 | };
33 |
34 | @Override
35 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
36 |
37 | byte[] v =MysqlStringUtils.readFixString(buf, pos, meta);
38 | StringBuilder sb = new StringBuilder();
39 | int index = 0;
40 | for(byte b : v) {
41 | for(int i = 0;i < 8; i++){
42 | if((b & ONES[i]) == ONES[i]) {
43 | sb.append(columnDef.getSetList().get(index * 8 + i));
44 | sb.append(",");
45 | }
46 | }
47 | }
48 |
49 | return sb.substring(0,sb.length() - 1);
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/StringColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
7 | import com.hiriver.unbiz.mysql.lib.protocol.tool.StringTool;
8 |
9 | /**
10 | * var char, var string, string
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class StringColumnTypeValueParser implements ColumnTypeValueParser {
16 |
17 | @Override
18 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
19 | // 注意,当column type is Type_String时, 这儿的meta不是mysql的meta,已经被转换过
20 | // see BaseRowEvent#parseEachColumnOfRow
21 | // meta is the max length of the column
22 | int len = 0;
23 | if (meta < 256) {
24 | len = (int) MysqlNumberUtils.read1Int(buf, pos);
25 | } else {
26 | len = (int) MysqlNumberUtils.read2Int(buf, pos);
27 | }
28 |
29 | return StringTool.safeConvertBytes2String(MysqlStringUtils.readFixString(buf, pos, len),
30 | columnDef.getCharset());
31 |
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/TimeColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import java.sql.Time;
4 | import java.util.Calendar;
5 |
6 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
7 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
8 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
9 |
10 | /**
11 | * time 类型解析器
12 | *
13 | * @author hexiufeng
14 | *
15 | */
16 | public class TimeColumnTypeValueParser implements ColumnTypeValueParser {
17 |
18 | @Override
19 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
20 | Calendar calendar = Calendar.getInstance();
21 | calendar.set(Calendar.MILLISECOND, 0);
22 | int tmp = MysqlNumberUtils.read3Int(buf, pos);
23 | calendar.set(0, 0, 0, tmp / 10000, (tmp % 10000) / 100, tmp % 100);
24 | return new Time(calendar.getTimeInMillis());
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/TimeStamp2ColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import java.sql.Timestamp;
4 |
5 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
6 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
7 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
8 |
9 | /**
10 | * timestamp2类型解析器
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class TimeStamp2ColumnTypeValueParser implements ColumnTypeValueParser {
16 |
17 | @Override
18 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
19 | long secValue = MysqlNumberUtils.readBigEdianNInt(buf, pos, 4);
20 | long usecValue = 0;
21 | switch (meta) {
22 | case 0:
23 | default:
24 | break;
25 | case 1:
26 | case 2:
27 | usecValue = MysqlNumberUtils.read1Int(buf, pos) * 10000L;
28 | break;
29 | case 3:
30 | case 4:
31 | usecValue = MysqlNumberUtils.readBigEdianNInt(buf, pos, 2) * 100;
32 | break;
33 | case 5:
34 | case 6:
35 | usecValue = MysqlNumberUtils.readBigEdianNInt(buf, pos, 3);
36 | }
37 | Timestamp tsValue = new Timestamp(secValue*1000);
38 | tsValue.setNanos((int) usecValue);
39 | return tsValue;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/TimeStampColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import java.sql.Timestamp;
4 |
5 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
6 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
7 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
8 |
9 | /**
10 | * timestamp类型解析器
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class TimeStampColumnTypeValueParser implements ColumnTypeValueParser {
16 |
17 | @Override
18 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
19 | long secValue = MysqlNumberUtils.readNInt(buf, pos, 4);
20 | secValue *=1000;
21 | return new Timestamp(secValue);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/UnsupportColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 |
6 | /**
7 | * 通用的描述不支持的数据类型,直接返回null
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public class UnsupportColumnTypeValueParser implements ColumnTypeValueParser {
13 |
14 | @Override
15 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
16 | return null;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binary/YearColumnTypeValueParser.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binary;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 |
7 | /**
8 | * year类型解析器
9 | *
10 | * @author hexiufeng
11 | *
12 | */
13 | public class YearColumnTypeValueParser implements ColumnTypeValueParser {
14 |
15 | @Override
16 | public Object parse(byte[] buf, Position pos, ColumnDefinition columnDef, int meta) {
17 | int value = MysqlNumberUtils.read1Int(buf, pos);
18 | return value + 1900;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/AbstractBinlogResponse.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Response;
4 |
5 | /**
6 | * 抽象描述同步binlog的返回数据包
7 | *
8 | * @author hexiufeng
9 | *
10 | */
11 | public abstract class AbstractBinlogResponse implements Response {
12 |
13 | @Override
14 | public void parse(byte[] buf) {
15 | throw new RuntimeException("don't support this method.");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/AbstractTableMetaProvider.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.TextProtocolBlockingTransport;
4 | import com.hiriver.unbiz.mysql.lib.TextProtocolBlockingTransportImpl;
5 | import com.hiriver.unbiz.mysql.lib.TransportConfig;
6 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
7 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.event.TableMapEvent;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.util.HashMap;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | abstract class AbstractTableMetaProvider implements TableMetaProvider {
16 | protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractTableMetaProvider.class);
17 | final Map cache = new HashMap();
18 | @Override
19 | public TableMeta getTableMeta(long tableId, TableMapEvent tableMapEvent) {
20 | String schemaName = tableMapEvent.getSchema();
21 | String tableName = tableMapEvent.getTableName();
22 | String fullTableName = schemaName + "." + tableName;
23 | if (cache.containsKey(fullTableName)) {
24 | TableMeta tableMeta = cache.get(fullTableName);
25 | if (tableMeta.getTableId() == tableId) {
26 | return tableMeta;
27 | }
28 | }
29 | TableMeta tableMeta = new TableMeta(tableId);
30 | TextProtocolBlockingTransport textTrans = new TextProtocolBlockingTransportImpl(getHost(), getPort(),
31 | getUserName(), getPassword(), schemaName, getTransportConfig());
32 |
33 | textTrans.open();
34 | try {
35 | List list = readMeta(tableName,tableMapEvent,textTrans);
36 | if(list != null && list.size() > 0) {
37 | tableMeta.getColumnMetaList().addAll(list);
38 | }
39 | } finally {
40 | textTrans.close();
41 | }
42 | cache.put(fullTableName, tableMeta);
43 | return tableMeta;
44 | }
45 |
46 | protected abstract String getHost();
47 | protected abstract int getPort();
48 | protected abstract String getUserName();
49 | protected abstract String getPassword();
50 | protected abstract TransportConfig getTransportConfig();
51 |
52 | protected abstract List readMeta(String tableName,TableMapEvent tableMapEvent, TextProtocolBlockingTransport textTrans);
53 | }
54 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/BinlogContext.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.event.FormatDescriptionEvent;
7 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.event.RotateEvent;
8 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.event.TableMapEvent;
9 |
10 | /**
11 | * 在binlog数据同步时,当前session的全局信息存储
12 | *
13 | * @author hexiufeng
14 | *
15 | */
16 | public class BinlogContext {
17 | /**
18 | * 表元数据的提供者,提供表字段、类型等
19 | */
20 | private TableMetaProvider tableMetaProvider;
21 | /**
22 | * 日志翻滚事件,用于描述当前或者将要正在发送binlog文件名称及position
23 | */
24 | private RotateEvent rotateEvent;
25 | /**
26 | * 当前binlog的事件格式描述事件,在执行同步命令后,mysql server 首先会发送Rotate event,之后会发送本事件。
27 | * 在整个sesition中只有这一个事件,其中的eventTypeHeaderLenArray属性会被用到
28 | */
29 | private FormatDescriptionEvent foramtDescEvent;
30 | /**
31 | * 当前事务的数据包所属表的元数据描述事件,不同的事务或者不同表的数据来临时,会有不同的 TableMapEvent发送过来,在这里缓存,用于后续数据的解析
32 | */
33 | // private TableMapEvent tableMapEvent;
34 |
35 | private final Map tableMapEventHolder = new HashMap<>();
36 | private final Map tableIdMapping = new HashMap<>();
37 |
38 |
39 |
40 | public TableMetaProvider getTableMetaProvider() {
41 | return tableMetaProvider;
42 | }
43 |
44 | public FormatDescriptionEvent getForamtDescEvent() {
45 | return foramtDescEvent;
46 | }
47 |
48 | public void putCurrentTableMapEvent(TableMapEvent tableMapEvent) {
49 | TableMapEvent old = tableMapEventHolder.get(tableMapEvent.getFullTableName());
50 | if(old != null && old.getTableId() != tableMapEvent.getTableId()){
51 | tableIdMapping.remove(old.getTableId());
52 | }
53 | tableMapEventHolder.put(tableMapEvent.getFullTableName(), tableMapEvent);
54 | tableIdMapping.put(tableMapEvent.getTableId(), tableMapEvent);
55 | }
56 |
57 | public TableMapEvent getTableMapEventByTableId(long tableId){
58 | return tableIdMapping.get(tableId);
59 | }
60 |
61 | public TableMapEvent getTableMapEventByFullTableName(String fullTableName){
62 | return tableMapEventHolder.get(fullTableName);
63 | }
64 |
65 | public void setTableMetaProvider(TableMetaProvider tableMetaProvider) {
66 | this.tableMetaProvider = tableMetaProvider;
67 | }
68 |
69 | public void setForamtDescEvent(FormatDescriptionEvent foramtDescEvent) {
70 | this.foramtDescEvent = foramtDescEvent;
71 | }
72 |
73 |
74 |
75 | public RotateEvent getRotateEvent() {
76 | return rotateEvent;
77 | }
78 |
79 | public void setRotateEvent(RotateEvent rotateEvent) {
80 | this.rotateEvent = rotateEvent;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/BinlogEvent.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Response;
4 |
5 | /**
6 | * 描述binlog事件的接口。binlog eventheader中提供当前事件的binlog位置和事件写入时间,
7 | * 这些信息会被应用方使用,尤其是调试时,非常有用,因此Binlog事件中需要携带这些信息。
8 | * binlog pos和Rotate 时间的binlog file name可以唯一确定当前事件在binlog file中的位置
9 | *
10 | * @author hexiufeng
11 | *
12 | */
13 | public interface BinlogEvent extends Response {
14 | /**
15 | * 获取当前事件在binlog file中的位置
16 | *
17 | * @return 当前事件在binlog file中的位置
18 | */
19 | long getBinlogEventPos();
20 | /**
21 | * 设置事件发生的时间
22 | *
23 | * @param occurTime 事件发生的时间
24 | */
25 | void acceptOccurTime(long occurTime);
26 | /**
27 | * 获取当前事件发生的时间
28 | * @return
29 | */
30 | long getOccurTime();
31 | }
32 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/BinlogEventHeader.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
4 | import com.hiriver.unbiz.mysql.lib.protocol.Response;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 |
7 | /**
8 | *
9 | * binlogEvent header,只支持 binlog verson 4
10 | *
11 | * @author hexiufeng
12 | *
13 | */
14 | public class BinlogEventHeader extends AbstractBinlogResponse implements Response {
15 | private int timestamp; // 4 bytes
16 | private int eventType; // 1 bytes
17 | private int serverId; // 4 bytes mysql server id
18 | private int eventSize; // 4 bytes
19 | private int logPos; // 4 bytes for binlog version >1
20 | private int flags; // 2 bytes for binlog version >1
21 |
22 | public int getRestContentLen() {
23 | return this.eventSize - getHeaderSize();
24 | }
25 |
26 | public int getHeaderSize() {
27 | return 19;
28 | }
29 |
30 | @Override
31 | public void parse(byte[] buf, Position pos) {
32 | this.timestamp = MysqlNumberUtils.read4Int(buf, pos);
33 | this.eventType = MysqlNumberUtils.read1Int(buf, pos);
34 | this.serverId = MysqlNumberUtils.read4Int(buf, pos);
35 | this.eventSize = MysqlNumberUtils.read4Int(buf, pos);
36 | this.logPos = MysqlNumberUtils.read4Int(buf, pos);
37 | this.flags = MysqlNumberUtils.read2Int(buf, pos);
38 | }
39 |
40 | public int getTimestamp() {
41 | return timestamp;
42 | }
43 |
44 | public int getEventType() {
45 | return eventType;
46 | }
47 |
48 | public int getServerId() {
49 | return serverId;
50 | }
51 |
52 | public int getLogPos() {
53 | return logPos;
54 | }
55 |
56 | public int getFlags() {
57 | return flags;
58 | }
59 |
60 | public void setTimestamp(int timestamp) {
61 | this.timestamp = timestamp;
62 | }
63 |
64 | public void setEventType(int eventType) {
65 | this.eventType = eventType;
66 | }
67 |
68 | public void setServerId(int serverId) {
69 | this.serverId = serverId;
70 | }
71 |
72 | public int getEventSize() {
73 | return eventSize;
74 | }
75 |
76 | public void setEventSize(int eventSize) {
77 | this.eventSize = eventSize;
78 | }
79 |
80 | public void setLogPos(int logPos) {
81 | this.logPos = logPos;
82 | }
83 |
84 | public void setFlags(int flags) {
85 | this.flags = flags;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/BinlogEventType.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | /**
4 | * mysql binlog所支持的binlog事件,copy在mysql的c源码
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public interface BinlogEventType {
10 | int UNKNOWN_EVENT = 0x00;
11 |
12 | int START_EVENT_V3 = 0x01;
13 |
14 | int QUERY_EVENT = 0x02;
15 |
16 | int STOP_EVENT = 0x03;
17 |
18 | int ROTATE_EVENT = 0x04;
19 |
20 | int INTVAR_EVENT = 0x05;
21 |
22 | int LOAD_EVENT = 0x06;
23 |
24 | int SLAVE_EVENT = 0x07;
25 |
26 | int CREATE_FILE_EVENT = 0x08;
27 |
28 | int APPEND_BLOCK_EVENT = 0x09;
29 |
30 | int EXEC_LOAD_EVENT = 0x0a;
31 |
32 | int DELETE_FILE_EVENT = 0x0b;
33 |
34 | int NEW_LOAD_EVENT = 0x0c;
35 |
36 | int RAND_EVENT = 0x0d;
37 |
38 | int USER_VAR_EVENT = 0x0e;
39 |
40 | int FORMAT_DESCRIPTION_EVENT = 0x0f;
41 |
42 | int XID_EVENT = 0x10;
43 |
44 | int BEGIN_LOAD_QUERY_EVENT = 0x11;
45 |
46 | int EXECUTE_LOAD_QUERY_EVENT = 0x12;
47 |
48 | int TABLE_MAP_EVENT = 0x13;
49 |
50 | int WRITE_ROWS_EVENTv0 = 0x14;
51 |
52 | int UPDATE_ROWS_EVENTv0 = 0x15;
53 |
54 | int DELETE_ROWS_EVENTv0 = 0x16;
55 |
56 | int WRITE_ROWS_EVENTv1 = 0x17;
57 |
58 | int UPDATE_ROWS_EVENTv1 = 0x18;
59 |
60 | int DELETE_ROWS_EVENTv1 = 0x19;
61 |
62 | int INCIDENT_EVENT = 0x1a;
63 |
64 | int HEARTBEAT_EVENT = 0x1b;
65 |
66 | int IGNORABLE_EVENT = 0x1c;
67 |
68 | int ROWS_QUERY_EVENT = 0x1d;
69 |
70 | int WRITE_ROWS_EVENTv2 = 0x1e;
71 |
72 | int UPDATE_ROWS_EVENTv2 = 0x1f;
73 |
74 | int DELETE_ROWS_EVENTv2 = 0x20;
75 |
76 | int GTID_EVENT = 0x21;
77 |
78 | int ANONYMOUS_GTID_EVENT = 0x22;
79 |
80 | int PREVIOUS_GTIDS_EVENT = 0x23;
81 | }
82 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/BinlogFileBinlogPosition.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Request;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.extra.BinlogPosition;
5 |
6 | /**
7 | * binlog file name + offset的实现,一般用于mysql5.6.9之前的版本,之后的版本请 使用{@link GTidBinlogPosition}
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public class BinlogFileBinlogPosition implements BinlogPosition {
13 | private long pos;
14 | private String binlogFileName;
15 |
16 | public BinlogFileBinlogPosition() {
17 |
18 | }
19 |
20 | public BinlogFileBinlogPosition(String binlogFileName, long pos) {
21 | this.pos = pos;
22 | this.binlogFileName = binlogFileName;
23 | }
24 |
25 | @Override
26 | public Request packetDumpRequest(int serverId) {
27 | DumpRequest request = new DumpRequest(pos, serverId, binlogFileName);
28 | return request;
29 | }
30 |
31 | @Override
32 | public byte[] toBytesArray() {
33 | return toString().getBytes();
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return binlogFileName + ":" + pos;
39 | }
40 |
41 | @Override
42 | public boolean isSame(BinlogPosition posStore) {
43 | if (!(posStore instanceof BinlogFileBinlogPosition)) {
44 | return false;
45 | }
46 | return toString().equals(posStore.toString());
47 | }
48 |
49 | public long getPos() {
50 | return pos;
51 | }
52 |
53 | public String getBinlogFileName() {
54 | return binlogFileName;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/DumpRequest.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.AbstractRequest;
4 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
5 | import com.hiriver.unbiz.mysql.lib.protocol.tool.SafeByteArrayOutputStream;
6 | import com.hiriver.unbiz.mysql.lib.protocol.tool.StringTool;
7 |
8 | /**
9 | * 基于binlog file name + offset的dump binlog指令实现,适用于COM_BINLOG_DUMP指令
10 | *
11 | * @author hexiufeng
12 | *
13 | */
14 | public class DumpRequest extends AbstractRequest {
15 | private final long pos;
16 | private final int serverId;
17 | private final String binlogFileName;
18 |
19 | public DumpRequest(long pos, int serverId, String binlogFileName) {
20 | this.pos = pos;
21 | this.serverId = serverId;
22 | this.binlogFileName = binlogFileName;
23 | }
24 |
25 | @Override
26 | protected void fillPayload(SafeByteArrayOutputStream out) {
27 | out.write(0x12);
28 | out.safeWrite(MysqlNumberUtils.write4Int((int) pos));
29 | out.safeWrite(MysqlNumberUtils.writeNInt(2, 2));
30 | out.safeWrite(MysqlNumberUtils.write4Int(serverId));
31 | out.safeWrite(StringTool.safeConvertString2Bytes(binlogFileName));
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/GTidBinlogPosition.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import java.util.Map;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import com.hiriver.unbiz.mysql.lib.protocol.Request;
9 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.extra.BinlogPosition;
10 |
11 | /**
12 | * 基于gtid的同步点实现,适用于mysql5.6.9之后的版本
13 | *
14 | * @author hexiufeng
15 | *
16 | */
17 | public class GTidBinlogPosition implements BinlogPosition {
18 | private static final Logger LOGGER = LoggerFactory.getLogger(GTidBinlogPosition.class);
19 | private GtIdSet gtidset;
20 |
21 | public GTidBinlogPosition() {
22 | }
23 |
24 | public GTidBinlogPosition(String gtIdSetString) {
25 | this.gtidset = new GtIdSet(gtIdSetString);
26 | }
27 |
28 | @Override
29 | public Request packetDumpRequest(int serverId) {
30 | if (LOGGER.isInfoEnabled()) {
31 | LOGGER.info("dump binlog use gtid set {}.", gtidset);
32 | }
33 | GTidDumpRequest request = new GTidDumpRequest(gtidset.getGtidMap(), serverId);
34 | return request;
35 | }
36 |
37 | @Override
38 | public byte[] toBytesArray() {
39 | return toString().getBytes();
40 | }
41 |
42 | public GtIdSet getGtidset() {
43 | return gtidset;
44 | }
45 |
46 | public void setGtidset(GtIdSet gtidset) {
47 | this.gtidset = gtidset;
48 | }
49 |
50 | public GTidBinlogPosition fixConfPos() {
51 | Map gtIdMap = gtidset.cloneGtIdMap();
52 | StringBuilder sb = new StringBuilder();
53 | int count = 0;
54 | for (String uuid : gtIdMap.keySet()) {
55 | if (count < gtIdMap.size() - 1) {
56 | sb.append(gtIdMap.get(uuid).cloneNextGtId().toString());
57 | } else {
58 | sb.append(gtIdMap.get(uuid).cloneGtId().toString());
59 | }
60 | sb.append(",");
61 | count++;
62 | }
63 | return new GTidBinlogPosition(sb.substring(0, sb.length() - 1));
64 | }
65 |
66 | @Override
67 | public String toString() {
68 | return gtidset.toString();
69 | }
70 |
71 | @Override
72 | public boolean isSame(BinlogPosition posStore) {
73 | if (!(posStore instanceof GTidBinlogPosition)) {
74 | return false;
75 | }
76 | return toString().equals(posStore.toString());
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/GTidDumpRequest.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import java.util.Map;
4 |
5 | import com.hiriver.unbiz.mysql.lib.protocol.AbstractRequest;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
7 | import com.hiriver.unbiz.mysql.lib.protocol.tool.GTSidTool;
8 | import com.hiriver.unbiz.mysql.lib.protocol.tool.SafeByteArrayOutputStream;
9 |
10 | /**
11 | * 基于gtid的dump指令实现,适用于COM_BINLOG_DUMP_GTID指令
12 | *
13 | * @author hexiufeng
14 | *
15 | */
16 | public class GTidDumpRequest extends AbstractRequest {
17 | private final int serverId;
18 | private final Map gtidInfoMap;
19 |
20 | public GTidDumpRequest(Map gtidInfoMap, int serverId) {
21 | this.gtidInfoMap = gtidInfoMap;
22 | this.serverId = serverId;
23 | }
24 |
25 | @Override
26 | protected void fillPayload(SafeByteArrayOutputStream out) {
27 | out.write(0x1e); // command
28 | out.safeWrite(MysqlNumberUtils.writeNInt(0x04, 2)); // flag
29 | out.safeWrite(MysqlNumberUtils.writeNInt(serverId, 4)); // server id
30 | out.safeWrite(MysqlNumberUtils.writeNInt(4, 4)); // binlog name size
31 | out.safeWrite(MysqlNumberUtils.writeNInt(0, 4)); // binlog name
32 | out.safeWrite(MysqlNumberUtils.writeNLong(4L, 8)); // binlog_pos
33 |
34 | out.safeWrite(MysqlNumberUtils.writeNInt(calDataLen(gtidInfoMap.size()), 4)); // datalen
35 |
36 | out.safeWrite(MysqlNumberUtils.writeNLong(gtidInfoMap.size(), 8)); // n_sids
37 |
38 | for (String uuid : gtidInfoMap.keySet()) {
39 | out.safeWrite(GTSidTool.convertSidString2DumpFormatBytes(uuid)); // sid
40 | GtId gi = gtidInfoMap.get(uuid);
41 |
42 | out.safeWrite(MysqlNumberUtils.writeNLong(1L, 8)); // n_intervals
43 | out.safeWrite(MysqlNumberUtils.writeNLong(gi.getInternel().getStart(), 8)); // start
44 | out.safeWrite(MysqlNumberUtils.writeNLong(gi.getInternel().getStop()==1?2:gi.getInternel().getStop(), 8)); // stop
45 | }
46 | }
47 |
48 | private int calDataLen(int nSids) {
49 | return nSids * 40 + 8;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/GtId.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import java.util.UUID;
4 |
5 | /**
6 | * 单个gtid,uuid:[12-]45
7 | *
8 | * @author hexiufeng
9 | *
10 | */
11 | public class GtId {
12 | private final String uuid;
13 | private GtIdInterval internel;
14 |
15 | public void setInternel(GtIdInterval internel) {
16 | this.internel = internel;
17 | }
18 |
19 | public GtId(String uuid, long start, long stop) {
20 | this.uuid = uuid;
21 | this.internel = new GtIdInterval(start,stop);
22 | }
23 |
24 | /**
25 | * 构造器
26 | *
27 | * @param gtidInfoString uuid:[3-]12
28 | */
29 | public GtId(String gtidInfoString) {
30 | String[] array = gtidInfoString.split(":");
31 | uuid = array[0];
32 | UUID.fromString(uuid);
33 | this.internel = new GtIdInterval(array[1]);
34 | }
35 |
36 | public String getUuid() {
37 | return uuid;
38 | }
39 |
40 |
41 | public GtIdInterval getInternel() {
42 | return internel;
43 | }
44 |
45 | @Override
46 | public String toString(){
47 | return this.uuid + ":" + internel.toShortString();
48 | }
49 |
50 |
51 | public GtId cloneGtId(){
52 | return new GtId(uuid,internel.getStart(),internel.getStop());
53 | }
54 |
55 | public GtId cloneNextGtId(){
56 | return new GtId(uuid,internel.getStart(),internel.getStop() + 1L);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/GtIdInterval.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | /**
4 | * 描述gtid的事务段
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class GtIdInterval {
10 | private final long start;
11 | private final long stop;
12 |
13 | public GtIdInterval(String internelString) {
14 | long end = 0;
15 | if (internelString.indexOf('-') >= 0) {
16 | String[] numPosArray = internelString.split("-");
17 | this.start = Long.parseLong(numPosArray[0]);
18 | end = Long.parseLong(numPosArray[1]);
19 | } else {
20 | this.start = 1L;
21 | end = Long.parseLong(internelString);
22 | }
23 | // if (end == 1L) {
24 | // end++;
25 | // }
26 | this.stop = end;
27 | }
28 |
29 | public GtIdInterval(long start, long stop) {
30 | this.start = start;
31 | this.stop = stop;
32 | }
33 |
34 | public long getStart() {
35 | return start;
36 | }
37 |
38 | public long getStop() {
39 | return stop;
40 | }
41 |
42 | public String toShortString() {
43 | return "" + stop;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/GtIdSet.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import java.util.Collections;
4 | import java.util.LinkedHashMap;
5 | import java.util.Map;
6 |
7 | /**
8 | * gtid set 描述
9 | *
10 | * @author hexiufeng
11 | *
12 | */
13 | public class GtIdSet {
14 | private final Map gtidMap = new LinkedHashMap<>();
15 |
16 | /**
17 | * uuid:[2-]13,uuid:[3-]19
18 | *
19 | * @param gtIdSetString gtid st string
20 | */
21 | public GtIdSet(String gtIdSetString) {
22 | gtIdSetString = gtIdSetString.replace("\n", "").replace(" ", "");
23 | String[] gtidArray = gtIdSetString.split(",");
24 | for (String gtid : gtidArray) {
25 | GtId gi = new GtId(gtid);
26 | if (gtidMap.containsKey(gi.getUuid())) {
27 | throw new RuntimeException("uuid must be unique.");
28 | }
29 | gtidMap.put(gi.getUuid(), gi);
30 | }
31 | }
32 |
33 | @Override
34 | public String toString() {
35 | StringBuilder sb = new StringBuilder();
36 | for (String uuid : this.gtidMap.keySet()) {
37 | GtId gi = gtidMap.get(uuid);
38 | sb.append(gi.toString());
39 | sb.append(",");
40 | }
41 | return sb.substring(0, sb.length() - 1);
42 | }
43 |
44 | public Map getGtidMap() {
45 | return Collections.unmodifiableMap(gtidMap);
46 | }
47 |
48 | public Map cloneGtIdMap() {
49 | Map clone = new LinkedHashMap<>();
50 | for (String uuid : gtidMap.keySet()) {
51 | clone.put(uuid, gtidMap.get(uuid).cloneGtId());
52 | }
53 | return clone;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/InternelColumnDefinition.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.ColumnType;
4 | import com.hiriver.unbiz.mysql.lib.protocol.tool.GenericStringTypeChecker;
5 |
6 | /**
7 | * 内部使用的表的列定义
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public class InternelColumnDefinition {
13 | private ColumnType columnType;
14 | /**
15 | * 主从复制协议中定义的每个字段的元数据,TableMapEvent会定义每一列的元数据,
16 | * 而元数据所占的长度跟类型有关,参见http://dev.mysql.com/doc/internals/en/table-map-event.html
17 | */
18 | private int meta;
19 | private boolean isNull;
20 |
21 | /**
22 | * 该字段是否是枚举或者set
23 | */
24 | private boolean enumOrSet;
25 |
26 | public InternelColumnDefinition(ColumnType columnType, int meta, boolean isNull) {
27 | this.columnType = columnType;
28 | this.meta = meta;
29 | this.isNull = isNull;
30 | // 枚举或set在内部也用string表示,需要区分开来
31 | if(columnType == ColumnType.MYSQL_TYPE_STRING){
32 | int[] lenghHolder = {0};
33 | ColumnType realType = GenericStringTypeChecker.checkRealColumnType(meta,lenghHolder);
34 | if(realType == ColumnType.MYSQL_TYPE_ENUM || realType == ColumnType.MYSQL_TYPE_SET){
35 | enumOrSet = true;
36 | }
37 | }
38 | }
39 |
40 | public ColumnType getColumnType() {
41 | return columnType;
42 | }
43 |
44 | public int getMeta() {
45 | return meta;
46 | }
47 |
48 | public boolean isNull() {
49 | return isNull;
50 | }
51 |
52 | public boolean isEnumOrSet(){
53 | return enumOrSet;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/RegisterRequest.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.AbstractRequest;
4 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
5 | import com.hiriver.unbiz.mysql.lib.protocol.tool.SafeByteArrayOutputStream;
6 |
7 | /**
8 | * 注册从库到主库请求指令,实现COM_REGISTER_SLAVE
9 | *
10 | * @author hexiufeng
11 | *
12 | */
13 | public class RegisterRequest extends AbstractRequest {
14 | private final int serverId;
15 |
16 | public RegisterRequest(int serverId) {
17 | this.serverId = serverId;
18 | }
19 |
20 | @Override
21 | protected void fillPayload(SafeByteArrayOutputStream out) {
22 | out.write(0x15);
23 | out.safeWrite(MysqlNumberUtils.write4Int(serverId));
24 | out.write(0);
25 | out.write(0);
26 | out.write(0);
27 | out.safeWrite(MysqlNumberUtils.writeNInt(0, 2));
28 | out.safeWrite(MysqlNumberUtils.write4Int(0));
29 | out.safeWrite(MysqlNumberUtils.write4Int(0));
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/TableMeta.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
7 |
8 | /**
9 | * table的元数据描述,主要包含字段的定义,包括字段名称,类型、是否为主键等
10 | *
11 | * @author hexiufeng
12 | *
13 | */
14 | public class TableMeta {
15 | private final List columnMetaList = new ArrayList();
16 | /**
17 | * tableid,mysql主从复制中的概念,标示一个表的唯一id,确切的说是mysql server缓存中针对每一个表分配的id,同一个表的id会变化.
18 | *
19 | * - 当mysql缓存刷新时,一个的表的id会发生变化
20 | * - 当表结构修改是,tableid会发生变化
21 | *
22 | */
23 | private final long tableId;
24 |
25 | public TableMeta(long tableId) {
26 | this.tableId = tableId;
27 | }
28 |
29 | public void addColumn(ColumnDefinition meta) {
30 | this.columnMetaList.add(meta);
31 | }
32 |
33 | public List getColumnMetaList() {
34 | return columnMetaList;
35 | }
36 |
37 | public ColumnDefinition getColumnDefinition(int index) {
38 | return this.columnMetaList.get(index);
39 | }
40 |
41 | public long getTableId() {
42 | return tableId;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/TableMetaProvider.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.event.TableMapEvent;
4 |
5 | /**
6 | * 表的元数据提供者,缺省实现是从mysql server读取。
7 | *
8 | * @author hexiufeng
9 | *
10 | */
11 | public interface TableMetaProvider {
12 | /**
13 | * 根据表的id和表名称获取表元数据
14 | *
15 | * @param tableId tableid
16 | * @param tableMapEvent tableMapEvent
17 | * @return 表的元数据
18 | */
19 | TableMeta getTableMeta(long tableId, TableMapEvent tableMapEvent);
20 | }
21 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/TimestampBinlogPosition.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Request;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.extra.BinlogPosition;
5 |
6 | /**
7 | *
8 | * 基于时间戳的位点,包含时间戳、mysql server uuid、binlog文件名称、文件内偏移量 4个字段;
9 | * 有效格式包含如下3种
10 | * 1543374986
11 | * 1543374986:::
12 | * 1543374686:a20181c1-7edb-11e6-8e14-90e2bac75fc4:mysql-bin.000178:515628788
13 | * 即或者只有时间戳或者有全部4个字段
14 | *
15 | * created by Yang Huawei (xander.yhw@alibaba-inc.com) on 2018/8/29 22:23
16 | */
17 | public class TimestampBinlogPosition implements BinlogPosition {
18 | /**
19 | * unix时间戳,单位秒
20 | */
21 | private final long timestamp;
22 | private final String serverUuid;
23 | private final String binlogFileName;
24 | private final Long pos;
25 |
26 |
27 | public TimestampBinlogPosition(long timestamp) {
28 | this(timestamp, null, null, null);
29 | }
30 |
31 | public TimestampBinlogPosition(long timestamp, String serverUuid, String binlogFileName,
32 | Long pos) {
33 | this.timestamp = timestamp;
34 | this.serverUuid = serverUuid;
35 | this.binlogFileName = binlogFileName;
36 | this.pos = pos;
37 | }
38 |
39 | @Override
40 | public Request packetDumpRequest(int serverId) {
41 | return new BinlogFileBinlogPosition(this.binlogFileName, this.pos).packetDumpRequest(serverId);
42 | }
43 |
44 | @Override
45 | public byte[] toBytesArray() {
46 | return toString().getBytes();
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | return timestamp + ":" + (serverUuid == null ? "" : serverUuid) + ":"
52 | + (binlogFileName == null ? "" : binlogFileName) + ":" + (pos == null ? "" : pos);
53 | }
54 |
55 | @Override
56 | public boolean isSame(BinlogPosition pos) {
57 | return this.equals(pos);
58 | }
59 |
60 |
61 | public long getTimestamp() {
62 | return timestamp;
63 | }
64 |
65 | public String getServerUuid() {
66 | return serverUuid;
67 | }
68 |
69 | public Long getPos() {
70 | return pos;
71 | }
72 |
73 | public String getBinlogFileName() {
74 | return binlogFileName;
75 | }
76 |
77 |
78 | @Override
79 | public boolean equals(Object o) {
80 | if (this == o)
81 | return true;
82 | if (o == null || getClass() != o.getClass())
83 | return false;
84 |
85 | TimestampBinlogPosition that = (TimestampBinlogPosition) o;
86 |
87 | if (timestamp != that.timestamp)
88 | return false;
89 | if (serverUuid != null ? !serverUuid.equals(that.serverUuid) : that.serverUuid != null)
90 | return false;
91 | if (binlogFileName != null ? !binlogFileName.equals(that.binlogFileName)
92 | : that.binlogFileName != null)
93 | return false;
94 | return pos != null ? pos.equals(that.pos) : that.pos == null;
95 | }
96 |
97 | @Override
98 | public int hashCode() {
99 | int result = (int) (timestamp ^ (timestamp >>> 32));
100 | result = 31 * result + (serverUuid != null ? serverUuid.hashCode() : 0);
101 | result = 31 * result + (binlogFileName != null ? binlogFileName.hashCode() : 0);
102 | result = 31 * result + (pos != null ? pos.hashCode() : 0);
103 | return result;
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/ValidBinlogOutput.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.event.BaseRowEvent;
4 |
5 | /**
6 | * 描述有效的binlog 数据 event。有效的数据evetn包括:
7 | *
8 | *
9 | * - Insert/update/delete row event
10 | * - GTId event
11 | * - XidEvent
12 | *
13 | *
14 | * @author hexiufeng
15 | *
16 | */
17 | public class ValidBinlogOutput {
18 | /**
19 | * 有效事件
20 | */
21 | private final BinlogEvent event;
22 | /**
23 | * binlog文件名称,配合event中的pos可以确定当前事件在binlog file中的位置
24 | */
25 | private final String binlogFileName;
26 | /**
27 | * 当前事件的类型
28 | */
29 | private final ValidEventType eventType;
30 |
31 | private String serverUuid;
32 |
33 | public ValidBinlogOutput(BinlogEvent event,String binlogFileName,ValidEventType eventType) {
34 | this.event = event;
35 | this.binlogFileName = binlogFileName;
36 | this.eventType = eventType;
37 | }
38 |
39 | public ValidEventType getEventType() {
40 | return eventType;
41 | }
42 |
43 | public String getBinlogFileName() {
44 | return binlogFileName;
45 | }
46 |
47 | /**
48 | * 当前事件是否是行数据事件
49 | *
50 | * @return boolean
51 | */
52 | public boolean isRowEvent() {
53 | return eventType == ValidEventType.ROW;
54 | }
55 | public BaseRowEvent getRowEvent(){
56 | return (BaseRowEvent)event;
57 | }
58 | public BinlogEvent getEvent() {
59 | return event;
60 | }
61 |
62 | public String getEventBinlogPos(){
63 | return binlogFileName + ":" + getEvent().getBinlogEventPos();
64 | }
65 |
66 | public String getServerUuid() {
67 | return serverUuid;
68 | }
69 |
70 | public void setServerUuid(String serverUuid) {
71 | this.serverUuid = serverUuid;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/ValidEventType.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog;
2 |
3 | /**
4 | * 描述有效事件的类型。
5 | *
6 | *
7 | * - 开始事务
8 | * - 事务提交
9 | * - 事务回滚
10 | * - 描述GTID的事件
11 | * - 行数据事件
12 | *
13 | *
14 | * @author hexiufeng
15 | *
16 | */
17 | public enum ValidEventType {
18 | TRAN_BEGIN,TRANS_COMMIT,TRANS_ROLLBACK,GTID,ROW;
19 | }
20 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/AbstractBinlogEvent.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.AbstractBinlogResponse;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
5 |
6 | /**
7 | * 抽象的binlog 事件描述
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public abstract class AbstractBinlogEvent extends AbstractBinlogResponse implements BinlogEvent {
13 | /**
14 | * 该事件在binlog file内部的位置
15 | */
16 | private final long eventBinlogPos;
17 | /**
18 | * 该数据写入mysql的事件戳,一般用于检测数据同步的性能
19 | */
20 | private long occurTime;
21 | /**
22 | * mysql日志是否支持校验
23 | */
24 | private final boolean hasCheckSum;
25 |
26 | protected AbstractBinlogEvent(long eventBinlogPos, boolean hasCheckSum) {
27 | this.eventBinlogPos = eventBinlogPos;
28 | this.hasCheckSum = hasCheckSum;
29 | }
30 |
31 | public boolean isHasCheckSum() {
32 | return hasCheckSum;
33 | }
34 |
35 | @Override
36 | public long getBinlogEventPos() {
37 | return eventBinlogPos;
38 | }
39 |
40 | @Override
41 | public void acceptOccurTime(long occurTime) {
42 | this.occurTime = occurTime;
43 | }
44 |
45 | @Override
46 | public long getOccurTime() {
47 | return occurTime;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/EventFactory.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogContext;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
5 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEventType;
6 |
7 | /**
8 | * 根据事件类型产生事件对象的工厂
9 | *
10 | * @author hexiufeng
11 | *
12 | */
13 | public class EventFactory {
14 | public static BinlogEvent factory(final int eventType, final long binlogEventPos, final BinlogContext context,
15 | boolean hasCheckSum) {
16 | switch (eventType) {
17 | case BinlogEventType.FORMAT_DESCRIPTION_EVENT:
18 | return new FormatDescriptionEvent(binlogEventPos, hasCheckSum);
19 | case BinlogEventType.GTID_EVENT:
20 | return new GTidEvent(binlogEventPos, hasCheckSum);
21 | case BinlogEventType.QUERY_EVENT:
22 | return new QueryEvent(binlogEventPos, hasCheckSum);
23 | case BinlogEventType.ROTATE_EVENT:
24 | return new RotateEvent(binlogEventPos, hasCheckSum);
25 | case BinlogEventType.WRITE_ROWS_EVENTv0:
26 | case BinlogEventType.UPDATE_ROWS_EVENTv0:
27 | case BinlogEventType.DELETE_ROWS_EVENTv0:
28 | return new RowEventV0(context, context.getTableMetaProvider(), eventType,
29 | binlogEventPos, hasCheckSum);
30 | case BinlogEventType.WRITE_ROWS_EVENTv1:
31 | case BinlogEventType.UPDATE_ROWS_EVENTv1:
32 | case BinlogEventType.DELETE_ROWS_EVENTv1:
33 | return new RowEventV1(context, context.getTableMetaProvider(), eventType,
34 | binlogEventPos, hasCheckSum);
35 | case BinlogEventType.WRITE_ROWS_EVENTv2:
36 | case BinlogEventType.UPDATE_ROWS_EVENTv2:
37 | case BinlogEventType.DELETE_ROWS_EVENTv2:
38 | return new RowEventV2(context, context.getTableMetaProvider(), eventType,
39 | binlogEventPos, hasCheckSum);
40 | case BinlogEventType.STOP_EVENT:
41 | return new StopEvent(binlogEventPos, hasCheckSum);
42 | case BinlogEventType.TABLE_MAP_EVENT:
43 | return new TableMapEvent(context.getForamtDescEvent(), binlogEventPos, hasCheckSum);
44 | case BinlogEventType.XID_EVENT:
45 | return new XidEvent(binlogEventPos, hasCheckSum);
46 | // case BinlogEventType.PREVIOUS_GTIDS_EVENT:
47 | // return new GTidEvent(binlogEventPos);
48 | default:
49 | return new UnkonwnEvent(binlogEventPos, hasCheckSum);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/FormatDescriptionEvent.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
7 |
8 | /**
9 | * mysql binlog格式描述事件,在mysql开始dump指令后,第二个发送的事件,一次dump指令只发送一次该事件,第一个事件是Rotate event
10 | *
11 | * @author hexiufeng
12 | *
13 | */
14 | public class FormatDescriptionEvent extends AbstractBinlogEvent implements BinlogEvent {
15 |
16 | private int binlogVersion; // 2 bytes
17 | private String mysqlSeverVersion; // 50 bytes
18 | private long createStamp; // 4 bytes, unix stamp
19 | private int eventHeaderLen; // 1 bytes, should be 19
20 | private byte[] eventTypeHeaderLenArray; // string.eof
21 |
22 | public FormatDescriptionEvent(long eventBinlogPos, boolean hasCheckSum) {
23 | super(eventBinlogPos, hasCheckSum);
24 | }
25 |
26 | @Override
27 | public void parse(byte[] buf, Position pos) {
28 | this.binlogVersion = MysqlNumberUtils.read2Int(buf, pos);
29 | this.mysqlSeverVersion = new String(MysqlStringUtils.readFixString(buf, pos, 50));
30 | this.createStamp = MysqlNumberUtils.read4Int(buf, pos) & 0xffffffffL;
31 | this.eventHeaderLen = MysqlNumberUtils.read1Int(buf, pos);
32 | this.eventTypeHeaderLenArray = MysqlStringUtils.readEofString(buf, pos, super.isHasCheckSum());
33 | }
34 |
35 | public int getPostHeaderLen(int eventType) {
36 | return eventTypeHeaderLenArray[eventType - 1] & 0xff;
37 | }
38 |
39 | public int getBinlogVersion() {
40 | return binlogVersion;
41 | }
42 |
43 | public String getMysqlSeverVersion() {
44 | return mysqlSeverVersion;
45 | }
46 |
47 | public long getCreateStamp() {
48 | return createStamp;
49 | }
50 |
51 | public int getEventHeaderLen() {
52 | return eventHeaderLen;
53 | }
54 |
55 | public byte[] getEventTypeHeaderLenArray() {
56 | return eventTypeHeaderLenArray;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/GTidEvent.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
7 | import com.hiriver.unbiz.mysql.lib.protocol.tool.GTSidTool;
8 |
9 | /**
10 | * gtid事件,在mysql5.6.9之后添加的事件,描述该事务的唯一id,在一个事务中,第一个被发送的事件
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class GTidEvent extends AbstractBinlogEvent implements BinlogEvent {
16 | private boolean commitFlag;
17 | private byte[] sid;
18 | private long gno;
19 |
20 | public GTidEvent(long eventBinlogPos, boolean hasCheckSum) {
21 | super(eventBinlogPos, hasCheckSum);
22 | }
23 |
24 | @Override
25 | public void parse(byte[] buf, Position pos) {
26 | int commitValue = MysqlNumberUtils.read1Int(buf, pos);
27 | commitFlag = commitValue == 1;
28 | sid = MysqlStringUtils.readFixString(buf, pos, 16);
29 | gno = MysqlNumberUtils.read8Int(buf, pos);
30 | }
31 |
32 | public String getGTidString() {
33 | return GTSidTool.convertSid2UUIDString(sid) + ":" + gno;
34 | }
35 |
36 | public boolean isCommitFlag() {
37 | return commitFlag;
38 | }
39 |
40 | public byte[] getSid() {
41 | return sid;
42 | }
43 |
44 | public String getSidString() {
45 | return GTSidTool.convertSid2UUIDString(sid);
46 | }
47 |
48 | public long getGno() {
49 | return gno;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/QueryEvent.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
7 |
8 | /**
9 | * 执行sql语句的事件,在binlog中一般保持开启、提交、回滚事件和ddl
10 | *
11 | * @author hexiufeng
12 | *
13 | */
14 | public class QueryEvent extends AbstractBinlogEvent implements BinlogEvent {
15 | private int slaveProxyId;
16 | private int executionTime;
17 | private int schemaLength;
18 | private int errorCode;
19 | private int statusVarsLength;
20 | private byte[] statusVars;
21 | private String schema;
22 | private String query;
23 |
24 | public QueryEvent(long eventBinlogPos, boolean hasCheckSum) {
25 | super(eventBinlogPos, hasCheckSum);
26 | }
27 |
28 | @Override
29 | public void parse(byte[] buf, Position pos) {
30 | this.slaveProxyId = MysqlNumberUtils.read4Int(buf, pos);
31 | this.executionTime = MysqlNumberUtils.read4Int(buf, pos);
32 | this.schemaLength = MysqlNumberUtils.read1Int(buf, pos);
33 | this.errorCode = MysqlNumberUtils.read2Int(buf, pos);
34 | this.statusVarsLength = MysqlNumberUtils.read2Int(buf, pos);
35 | this.statusVars = MysqlStringUtils.readFixString(buf, pos, statusVarsLength);
36 | this.schema = new String(MysqlStringUtils.readFixString(buf, pos, schemaLength));
37 | pos.forwardPos();
38 | this.query = new String(MysqlStringUtils.readEofString(buf, pos, super.isHasCheckSum()));
39 | }
40 |
41 | public int getSlaveProxyId() {
42 | return slaveProxyId;
43 | }
44 |
45 | public int getExecutionTime() {
46 | return executionTime;
47 | }
48 |
49 | public int getSchemaLength() {
50 | return schemaLength;
51 | }
52 |
53 | public int getErrorCode() {
54 | return errorCode;
55 | }
56 |
57 | public int getStatusVarsLength() {
58 | return statusVarsLength;
59 | }
60 |
61 | public byte[] getStatusVars() {
62 | return statusVars;
63 | }
64 |
65 | public String getSchema() {
66 | return schema;
67 | }
68 |
69 | public String getQuery() {
70 | return query;
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/RotateEvent.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
7 |
8 | /**
9 | * 日志翻滚事件,在执行dump指令后,后者开启新日志文件时,都会发送该事件,它可以记录后续事件所在的binlog file name,
10 | * 在非gtid支持的场景下,非常有用,可以用于记录事件所在的位置
11 | *
12 | * @author hexiufeng
13 | *
14 | */
15 | public class RotateEvent extends AbstractBinlogEvent implements BinlogEvent {
16 | private long position;
17 | private String nextBinlogName;
18 |
19 | public RotateEvent(long eventBinlogPos, boolean hasCheckSum) {
20 | super(eventBinlogPos, hasCheckSum);
21 | }
22 |
23 | @Override
24 | public void parse(byte[] buf, Position pos) {
25 | this.position = MysqlNumberUtils.read8Int(buf, pos);
26 | this.nextBinlogName = new String(MysqlStringUtils.readEofString(buf, pos, super.isHasCheckSum()));
27 | }
28 |
29 | public long getPosition() {
30 | return position;
31 | }
32 |
33 | public String getNextBinlogName() {
34 | return nextBinlogName;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/RowEventV0.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import java.util.Collections;
4 | import java.util.List;
5 |
6 | import com.hiriver.unbiz.mysql.lib.output.BinlogColumnValue;
7 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
8 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogContext;
9 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
10 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.TableMeta;
11 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.TableMetaProvider;
12 |
13 | /**
14 | * 行事件,版本0
15 | *
16 | * @author hexiufeng
17 | *
18 | */
19 | public class RowEventV0 extends BaseRowEvent implements BinlogEvent {
20 |
21 | public RowEventV0(BinlogContext binlogContext, TableMetaProvider tableMetaProvider, int eventType,
22 | final long eventBinlogPos, boolean hasCheckSum) {
23 | super(binlogContext, tableMetaProvider, eventType, eventBinlogPos, hasCheckSum);
24 | }
25 |
26 | @Override
27 | protected void parseVerPostHeader(byte[] buf, Position pos) {
28 | }
29 |
30 | @Override
31 | protected void parseVerBodyForUpdate(byte[] buf, Position pos) {
32 | // do nothing
33 | }
34 |
35 | @Override
36 | protected List parseVerRowForUpdate(byte[] buf, Position pos, TableMeta tableMeta) {
37 | return Collections.emptyList();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/RowEventV1.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import java.util.List;
4 |
5 | import com.hiriver.unbiz.mysql.lib.output.BinlogColumnValue;
6 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
7 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogContext;
8 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
9 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.TableMeta;
10 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.TableMetaProvider;
11 |
12 | /**
13 | * 行事件,版本2,支持获取update之前的数据。在子header后有2个字节的预留,解析时需要跳过。 mysql文档中在这个地方存在错误
14 | *
15 | * @author hexiufeng
16 | *
17 | */
18 | public class RowEventV1 extends BaseRowEvent implements BinlogEvent {
19 | private byte[] updateColumnsNotNullBitmap;
20 |
21 | public RowEventV1(BinlogContext binlogContext, TableMetaProvider tableMetaProvider, int eventType,
22 | final long eventBinlogPos, boolean hasCheckSum) {
23 | super(binlogContext, tableMetaProvider, eventType, eventBinlogPos, hasCheckSum);
24 | }
25 |
26 | @Override
27 | protected void parseVerPostHeader(byte[] buf, Position pos) {
28 | }
29 |
30 | @Override
31 | protected void parseVerBodyForUpdate(byte[] buf, Position pos) {
32 | updateColumnsNotNullBitmap = readNotNullBitmap(buf, pos);
33 | }
34 |
35 | @Override
36 | protected List parseVerRowForUpdate(byte[] buf, Position pos, TableMeta tableMeta) {
37 | return super.parseRow(updateColumnsNotNullBitmap, buf, pos, tableMeta);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/RowEventV2.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogContext;
5 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
6 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.TableMetaProvider;
7 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
8 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
9 |
10 | /**
11 | * 行事件,版本2
12 | *
13 | * @author hexiufeng
14 | *
15 | */
16 | public class RowEventV2 extends RowEventV1 implements BinlogEvent {
17 |
18 | public RowEventV2(BinlogContext binlogContext, TableMetaProvider tableMetaProvider, int eventType,
19 | final long eventBinlogPos, boolean hasCheckSum) {
20 | super(binlogContext, tableMetaProvider, eventType, eventBinlogPos, hasCheckSum);
21 | }
22 |
23 | @Override
24 | protected void parseVerPostHeader(byte[] buf, Position pos) {
25 | int len = MysqlNumberUtils.read2Int(buf, pos);
26 | MysqlStringUtils.readFixString(buf, pos, len - 2);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/StopEvent.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
5 |
6 | /**
7 | * stop event,无用
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public class StopEvent extends AbstractBinlogEvent implements BinlogEvent {
13 |
14 | public StopEvent(long eventBinlogPos, boolean hasCheckSum) {
15 | super(eventBinlogPos, hasCheckSum);
16 | }
17 |
18 | @Override
19 | public void parse(byte[] buf, Position pos) {
20 |
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/UnkonwnEvent.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
5 |
6 | /**
7 | * 未知事件,直接丢弃
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public class UnkonwnEvent extends AbstractBinlogEvent implements BinlogEvent {
13 |
14 | public UnkonwnEvent(long eventBinlogPos, boolean hasCheckSum) {
15 | super(eventBinlogPos, hasCheckSum);
16 | // TODO Auto-generated constructor stub
17 | }
18 |
19 | @Override
20 | public void parse(byte[] buf, Position pos) {
21 | // do nothing
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/event/XidEvent.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.event;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
4 | import com.hiriver.unbiz.mysql.lib.protocol.binlog.BinlogEvent;
5 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
6 |
7 | /**
8 | * Xid event,标志着事务的结束
9 | *
10 | * @author hexiufeng
11 | *
12 | */
13 | public class XidEvent extends AbstractBinlogEvent implements BinlogEvent {
14 | private long xid;
15 |
16 | public XidEvent(long eventBinlogPos, boolean hasCheckSum) {
17 | super(eventBinlogPos, hasCheckSum);
18 | }
19 |
20 | @Override
21 | public void parse(byte[] buf, Position pos) {
22 | this.xid = MysqlNumberUtils.read8Int(buf, pos);
23 | }
24 |
25 | public long getXid() {
26 | return xid;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/exp/FetalParseValueExp.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.exp;
2 |
3 | /**
4 | * 解析columnvalue失败时抛出的异常
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class FetalParseValueExp extends RuntimeException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | public FetalParseValueExp(Exception e){
17 | super(e);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/exp/InvalidBinlogVer.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.exp;
2 |
3 | /**
4 | * 无效的binlog版本异常
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class InvalidBinlogVer extends RuntimeException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/exp/InvalidColumnType.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.exp;
2 |
3 | /**
4 | * 无效的列类型异常,当不能识别列类型时抛出该异常
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class InvalidColumnType extends RuntimeException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | public InvalidColumnType(String message) {
17 | super(message);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/exp/ReadTimeoutExp.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.exp;
2 |
3 | /**
4 | * 读取数据超时异常。当没有新数据或者网络抖动时可能被抛出。
5 | * 上层应用应该捕获该异常并试图重新连接mysql
6 | *
7 | * @author hexiufeng
8 | *
9 | */
10 | public class ReadTimeoutExp extends RuntimeException {
11 |
12 | /**
13 | *
14 | */
15 | private static final long serialVersionUID = 1L;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/exp/TableAlreadyModifyExp.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.exp;
2 |
3 | /**
4 | * 表结构已经被修改异常,当接收到的binlog事件描述的列总数大于当前数据库
5 | * 中表的列数时,抛出该异常,表示表结构已经发生变化,将无法匹配到正确的列名
6 | *
7 | * @author hexiufeng
8 | *
9 | */
10 | public class TableAlreadyModifyExp extends RuntimeException {
11 |
12 | /**
13 | *
14 | */
15 | private static final long serialVersionUID = 1L;
16 |
17 | public TableAlreadyModifyExp(String message){
18 | super(message);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/binlog/extra/BinlogPosition.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.binlog.extra;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Request;
4 |
5 | /**
6 | * 描述mysql binlog的同步点。当一个事务结束时需要记录同步点,当重新同步时可以从该同步点继续同步。
7 | *
8 | *
9 | * - mysql5.6.9之前,同步点是binlog file name + offset
10 | * - mysql5.6.9之后,同步点可以是gtid,当从mysql从库复制数据时,当一个从库崩溃,可以自动切换到其他从库,此时 gtid特别有用,可以保证从正确的位置继续复制,但第一种方式不行
11 | *
12 | *
13 | * @author hexiufeng
14 | *
15 | */
16 | public interface BinlogPosition {
17 | /**
18 | * 转换binlog pos为dump指令
19 | *
20 | * @param serverId 从库的唯一id,当前系统逻辑上就是一个从库
21 | * @return dump指令请求
22 | */
23 | Request packetDumpRequest(int serverId);
24 |
25 | /**
26 | * 转换成可以存储的二进制流。缺省实现是调用当前对象的toString()方法,然后转换成byte数组
27 | *
28 | * @return byte 数组
29 | */
30 | byte[] toBytesArray();
31 |
32 | /**
33 | * 判断两个 pos是否相同
34 | *
35 | * @param pos 所比较的位置
36 | * @return 是否相同
37 | */
38 | boolean isSame(BinlogPosition pos);
39 | }
40 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/datautils/MysqlStringUtils.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.datautils;
2 |
3 | import java.util.Arrays;
4 |
5 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
6 | import com.hiriverunbiz.mysql.lib.exp.InvalidMysqlDataException;
7 |
8 | /**
9 | * 处理mysql string类型的数据工具,mysql string本质上是byte[].
10 | *
11 | * ses
12 | * http://dev.mysql.com/doc/internals/en/string.html
13 | *
14 | * @author hexiufeng
15 | *
16 | */
17 | public class MysqlStringUtils {
18 | private MysqlStringUtils() {
19 | }
20 |
21 | /**
22 | * 读取null结尾的string
23 | *
24 | * @param buf
25 | * @param off
26 | * @return
27 | */
28 | public static byte[] readNulString(byte[] buf, Position off) {
29 | int end = -1;
30 | int start = off.getPos();
31 | for (int i = start; i < buf.length; i++) {
32 | if (buf[i] == 0) {
33 | end = i;
34 | break;
35 | }
36 | }
37 | if (end == -1) {
38 | throw new InvalidMysqlDataException("invalid null string");
39 | }
40 | off.forwardPos(end + 1 - start);
41 | return Arrays.copyOfRange(buf, start, end);
42 | }
43 |
44 | /**
45 | * 读取指定长度的string
46 | *
47 | * @param buf
48 | * @param off
49 | * @param len
50 | * @return
51 | */
52 | public static byte[] readFixString(byte[] buf, Position off, int len) {
53 | int start = off.getPos();
54 | off.forwardPos(len);
55 | return Arrays.copyOfRange(buf, start, start + len);
56 | }
57 |
58 | /**
59 | * 从当前位置读取到最后的string
60 | *
61 | * @param buf
62 | * @param off
63 | * @return
64 | */
65 | public static byte[] readEofString(byte[] buf, Position off) {
66 | return readEofString(buf, off, false);
67 | }
68 |
69 | /**
70 | * 从当前位置读取到最后的string,不包含最好4个字节的校验码
71 | *
72 | * @param buf
73 | * @param off
74 | * @param hasCheckSum
75 | * @return
76 | */
77 | public static byte[] readEofString(byte[] buf, Position off, boolean hasCheckSum) {
78 | int len = buf.length - off.getPos();
79 | if (hasCheckSum) {
80 | len -= 4;
81 | }
82 | return readFixString(buf, off, len);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/AbstractTextCommandRequest.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.AbstractRequest;
4 |
5 | /**
6 | * 抽象的文本协议的 request命令
7 | *
8 | * @author hexiufeng
9 | *
10 | */
11 | public abstract class AbstractTextCommandRequest extends AbstractRequest {
12 | protected final int command;
13 |
14 | protected AbstractTextCommandRequest(int command) {
15 | this.command = command;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/ColumnValue.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 | import com.hiriver.unbiz.mysql.lib.output.ColumnDefinition;
4 |
5 | /**
6 | * 描述列的值
7 | *
8 | * @author hexiufeng
9 | *
10 | */
11 | public class ColumnValue {
12 | private final ColumnValueProvider provider;
13 | private final ColumnDefinition definition;
14 |
15 | public ColumnValue(ColumnValueProvider provider, ColumnDefinition definition) {
16 | this.provider = provider;
17 | this.definition = definition;
18 | provider.useCharset(definition.getCharset());
19 | }
20 |
21 | public boolean isNull() {
22 | return provider.isNull();
23 | }
24 |
25 | public String getValueAsString() {
26 | return provider.getValueAsString();
27 | }
28 |
29 | public Integer getValueAsInt() {
30 | return provider.getValueAsInt();
31 | }
32 |
33 | public Long getValueAsLong() {
34 | return provider.getValueAsLong();
35 | }
36 |
37 | public String getCharset() {
38 | return definition.getCharset();
39 | }
40 |
41 | public String getColumnName(){
42 | return definition.getColumName();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/ColumnValueProvider.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 |
4 | /**
5 | * 解析列值的提供者抽象。用于解析每列的值
6 | *
7 | * @author hexiufeng
8 | *
9 | */
10 | public interface ColumnValueProvider {
11 | /**
12 | * 解析成string类型
13 | *
14 | * @return string类型
15 | */
16 | String getValueAsString();
17 |
18 | /**
19 | * 解析成Integer值
20 | *
21 | * @return Integer值
22 | */
23 | Integer getValueAsInt();
24 |
25 | /**
26 | * 解析成long
27 | *
28 | * @return long值
29 | */
30 | Long getValueAsLong();
31 |
32 | /**
33 | * 是否是空值
34 | *
35 | * @return boolean
36 | */
37 | boolean isNull();
38 |
39 | /**
40 | * 当数据类型是string时,应该使用哪种charset来解析
41 | *
42 | * @param charset
43 | */
44 | void useCharset(String charset);
45 | }
46 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/FieldListCommandResponse.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.hiriver.unbiz.mysql.lib.ResultContentReader;
7 | import com.hiriver.unbiz.mysql.lib.protocol.AbstractResponse;
8 | import com.hiriver.unbiz.mysql.lib.protocol.Response;
9 | import com.hiriver.unbiz.mysql.lib.protocol.tool.PacketTool;
10 |
11 | /**
12 | * 描述COM_FIELD_LIST指令的返回结果,返回表的列定义
13 | *
14 | * @author hexiufeng
15 | *
16 | */
17 | public class FieldListCommandResponse extends AbstractResponse implements Response {
18 | private List columnList = new ArrayList(32);
19 |
20 | private final ResultContentReader resultContextReader;
21 |
22 | public FieldListCommandResponse(ResultContentReader resultContextReader) {
23 | this.resultContextReader = resultContextReader;
24 | }
25 |
26 | @Override
27 | public void parse(byte[] buf) {
28 | ColumnDefinitionResponse colDef = new ColumnDefinitionResponse(false);
29 | colDef.parse(buf);
30 | columnList.add(colDef);
31 | byte[] nextBuffer = resultContextReader.readNextPacketPayload();
32 | while (!PacketTool.isEofPacket(nextBuffer)) {
33 | ColumnDefinitionResponse nextColDef = new ColumnDefinitionResponse(false);
34 | nextColDef.parse(nextBuffer);
35 | columnList.add(nextColDef);
36 | nextBuffer = resultContextReader.readNextPacketPayload();
37 | }
38 | }
39 |
40 | public List getColumnList() {
41 | return columnList;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/PingRequest.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.Request;
4 | import com.hiriver.unbiz.mysql.lib.protocol.tool.SafeByteArrayOutputStream;
5 |
6 | /**
7 | * Ping command request
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public class PingRequest extends AbstractTextCommandRequest implements Request {
13 |
14 | public PingRequest() {
15 | super(0x0e);
16 | }
17 |
18 | @Override
19 | protected void fillPayload(SafeByteArrayOutputStream out) {
20 | out.write(super.command);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/ResultsetRowResponse.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.hiriver.unbiz.mysql.lib.protocol.AbstractResponse;
7 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
8 | import com.hiriver.unbiz.mysql.lib.protocol.Response;
9 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
10 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlStringUtils;
11 |
12 | /**
13 | * COM_QUERY指令返回结果中行数据部分描述
14 | *
15 | * @author hexiufeng
16 | *
17 | */
18 | public class ResultsetRowResponse extends AbstractResponse implements Response {
19 | private List valueList;
20 | private final List columnList;
21 |
22 | public List getValueList() {
23 | return valueList;
24 | }
25 |
26 | public ResultsetRowResponse(List columnList) {
27 | this.columnList = columnList;
28 | valueList = new ArrayList(columnList.size());
29 | }
30 |
31 | @Override
32 | public void parse(byte[] buf) {
33 | Position pos = Position.factory();
34 | for (int i = 0; i < columnList.size(); i++) {
35 | valueList.add(parseColumn(buf, i,pos));
36 | }
37 | }
38 |
39 | /**
40 | * 解析每一列的数据
41 | *
42 | * @param buf 二进制数据
43 | * @param column 列的index
44 | * @return 列值
45 | */
46 | private ColumnValue parseColumn(byte[] buf, int column,Position pos) {
47 |
48 | if ((buf[pos.getPos()] & 0xff) == 0xfb) {
49 | pos.forwardPos();
50 | return null;
51 | } else {
52 | int lenc = (int) MysqlNumberUtils.readLencodeLong(buf, pos);
53 | byte[] tb = MysqlStringUtils.readFixString(buf, pos, lenc);
54 | return new ColumnValue(new TextColumnValueProvider(tb), columnList.get(column).toColumnDefinition());
55 | }
56 |
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/TextColumnValueProvider.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 | import com.hiriver.unbiz.mysql.lib.CharsetMapping;
4 | import com.hiriver.unbiz.mysql.lib.protocol.tool.StringTool;
5 |
6 | /**
7 | * 支持文本协议的列数据解析提供者。{@link ColumnValueProvider}实现
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | class TextColumnValueProvider implements ColumnValueProvider {
13 | private final byte[] binValue;
14 | private String charset = "UTF-8";
15 | private boolean isConvert = false;
16 | private String convertedString;
17 |
18 | public TextColumnValueProvider(byte[] binValue) {
19 | this.binValue = binValue;
20 | }
21 |
22 | @Override
23 | public String getValueAsString() {
24 | if (!isConvert) {
25 | if (binValue == null) {
26 | convertedString = null;
27 | }
28 | if (CharsetMapping.isBinary(charset)) {
29 | convertedString = StringTool.safeConvertBytes2String(binValue);
30 | } else {
31 | convertedString = StringTool.safeConvertBytes2String(binValue, charset);
32 | }
33 | isConvert = true;
34 | }
35 |
36 | return convertedString;
37 | }
38 |
39 | @Override
40 | public Integer getValueAsInt() {
41 | if (isNull()) {
42 | return null;
43 | }
44 | return Integer.parseInt(getValueAsString());
45 | }
46 |
47 | @Override
48 | public Long getValueAsLong() {
49 | if (isNull()) {
50 | return null;
51 | }
52 | return Long.parseLong(getValueAsString());
53 | }
54 |
55 | @Override
56 | public void useCharset(String charset) {
57 | this.charset = charset;
58 | }
59 |
60 | @Override
61 | public boolean isNull() {
62 | return binValue == null;
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/TextCommandFieldListRequest.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.tool.SafeByteArrayOutputStream;
4 | import com.hiriver.unbiz.mysql.lib.protocol.tool.StringTool;
5 |
6 | /**
7 | * COM_FIELD_LIST指令实现,用于获取表的列定义
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public class TextCommandFieldListRequest extends AbstractTextCommandRequest {
13 | private String table; // string.nul
14 | private String fieldWildcard; // string.eof
15 |
16 | public TextCommandFieldListRequest() {
17 | super(0x04);
18 | }
19 |
20 | public TextCommandFieldListRequest(String table) {
21 | super(0x04);
22 | this.table = table;
23 | }
24 |
25 | @Override
26 | protected void fillPayload(SafeByteArrayOutputStream out) {
27 | out.write(super.command);
28 | out.safeWrite(StringTool.safeConvertString2Bytes(table));
29 | out.write(0);
30 | if (fieldWildcard != null && !fieldWildcard.isEmpty()) {
31 | out.safeWrite(StringTool.safeConvertString2Bytes(fieldWildcard));
32 | }
33 | }
34 |
35 | public String getTable() {
36 | return table;
37 | }
38 |
39 | public String getFieldWildcard() {
40 | return fieldWildcard;
41 | }
42 |
43 | public void setTable(String table) {
44 | this.table = table;
45 | }
46 |
47 | public void setFieldWildcard(String fieldWildcard) {
48 | this.fieldWildcard = fieldWildcard;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/TextCommandQueryRequest.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.tool.SafeByteArrayOutputStream;
4 | import com.hiriver.unbiz.mysql.lib.protocol.tool.StringTool;
5 |
6 | /**
7 | * COM_QUERY指令实现,用于执行sql
8 | *
9 | * @author hexiufeng
10 | *
11 | */
12 | public class TextCommandQueryRequest extends AbstractTextCommandRequest {
13 | private String query;
14 |
15 | public TextCommandQueryRequest() {
16 | super(0x03);
17 | }
18 |
19 | public TextCommandQueryRequest(String query) {
20 | super(0x03);
21 | this.query = query;
22 | }
23 |
24 | @Override
25 | protected void fillPayload(SafeByteArrayOutputStream out) {
26 | out.write(super.command);
27 | out.safeWrite(StringTool.safeConvertString2Bytes(query));
28 | }
29 |
30 | public String getQuery() {
31 | return query;
32 | }
33 |
34 | public void setQuery(String query) {
35 | this.query = query;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/text/TextCommandQueryResponse.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.text;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.hiriver.unbiz.mysql.lib.ResultContentReader;
7 | import com.hiriver.unbiz.mysql.lib.protocol.AbstractResponse;
8 | import com.hiriver.unbiz.mysql.lib.protocol.EOFPacket;
9 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
10 | import com.hiriver.unbiz.mysql.lib.protocol.Response;
11 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
12 | import com.hiriver.unbiz.mysql.lib.protocol.tool.PacketTool;
13 |
14 | /**
15 | * COM_QUERY指令的返回结果
16 | *
17 | * @author hexiufeng
18 | *
19 | */
20 | public class TextCommandQueryResponse extends AbstractResponse implements Response {
21 | private int columnCount;
22 | private List columnList = new ArrayList(32);
23 | private List rowList = new ArrayList();
24 |
25 | private final ResultContentReader resultContextReader;
26 |
27 | public TextCommandQueryResponse(ResultContentReader resultContextReader) {
28 | this.resultContextReader = resultContextReader;
29 | }
30 |
31 | @Override
32 | public void parse(byte[] buf) {
33 | Position pos = Position.factory();
34 | columnCount = (int) MysqlNumberUtils.readLencodeLong(buf, pos);
35 | readColumnDefinition(columnCount);
36 |
37 | byte[] rowBuffer = resultContextReader.readNextPacketPayload();
38 | while (!PacketTool.isEofPacket(rowBuffer, 0)) {
39 | // pasre row
40 | ResultsetRowResponse row = new ResultsetRowResponse(columnList);
41 | row.parse(rowBuffer);
42 | rowList.add(row);
43 | rowBuffer = resultContextReader.readNextPacketPayload();
44 | }
45 | }
46 |
47 | private void readColumnDefinition(int count) {
48 | for (int i = 0; i < count; i++) {
49 | ColumnDefinitionResponse colDef = new ColumnDefinitionResponse(true);
50 | colDef.parse(resultContextReader.readNextPacketPayload());
51 |
52 | columnList.add(colDef);
53 | }
54 | // parse eof
55 | EOFPacket eof = new EOFPacket();
56 | eof.parse(resultContextReader.readNextPacketPayload());
57 | }
58 |
59 | public List getColumnList() {
60 | return columnList;
61 | }
62 |
63 | public List getRowList() {
64 | return rowList;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/tool/GTSidTool.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.tool;
2 |
3 | /**
4 | * GTID工具,用于把byte数组转换成mysql uuid strig,或者把
5 | * uuid string转换成byte数据
6 | *
7 | * @author hexiufeng
8 | *
9 | */
10 | public class GTSidTool {
11 | private GTSidTool() {
12 |
13 | }
14 |
15 | private final static char[] HEX_DICT =
16 | { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
17 |
18 | /**
19 | * 把byte数组转换成mysql的uuid
20 | *
21 | * @param sid byte数组
22 | * @return uuid string
23 | */
24 | public static String convertSid2UUIDString(byte[] sid) {
25 | StringBuilder sb = new StringBuilder(36);
26 | for (int i = 0; i < 16; i++) {
27 | if (i == 4 || i == 6 || i == 8 || i == 10) {
28 | sb.append('-');
29 | }
30 | int value = sid[i] & 0xff;
31 | sb.append(HEX_DICT[value >> 4]);
32 | sb.append(HEX_DICT[value & 0xf]);
33 | }
34 | return sb.toString();
35 | }
36 |
37 | /**
38 | * 用于把mysql uuid转换成byte数组
39 | *
40 | * @param uuidString uuid string
41 | * @return byte数组
42 | */
43 | public static byte[] convertSidString2DumpFormatBytes(String uuidString) {
44 | String value = uuidString.replaceAll("-", "");
45 | byte[] buffer = new byte[16];
46 |
47 | for (int i = 0; i < 16; i++) {
48 | String hex = value.substring(2 * i, 2 * i + 2);
49 | int intValue = Integer.parseInt(hex, 16);
50 | buffer[i] = (byte) intValue;
51 | }
52 | return buffer;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/tool/GenericStringTypeChecker.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.tool;
2 |
3 | import com.hiriver.unbiz.mysql.lib.ColumnType;
4 |
5 | /**
6 | * Created by hexiufeng on 2017/5/28.
7 | */
8 | public class GenericStringTypeChecker {
9 | private GenericStringTypeChecker(){
10 |
11 | }
12 |
13 | /**
14 | * 针对于char类型所做的特殊处理,主要是重新修正length,参见log_event.cc#log_event_print_value
15 | *
16 | * @param meta column meta value
17 | * @param lengthHolder length占位符
18 | * @return
19 | */
20 | public static ColumnType checkRealColumnType(int meta, int[] lengthHolder) {
21 | // from log_event.cc
22 | if (meta >= 256) {
23 | // column type
24 | int byte0 = meta >>> 8;
25 | // length
26 | int byte1 = meta & 0xff;
27 |
28 | if ((byte0 & 0x30) != 0x30) {
29 | /* a long CHAR() field: see #37426 */
30 | lengthHolder[0] = byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
31 |
32 | return ColumnType.ofTypeValue(byte0 | 0x30);
33 | }
34 |
35 | lengthHolder[0] = meta & 0xff;
36 | return ColumnType.ofTypeValue(byte0);
37 |
38 | }
39 | lengthHolder[0] = meta;
40 | return ColumnType.MYSQL_TYPE_STRING;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/tool/PacketTool.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.tool;
2 |
3 | /**
4 | * 判断common packet类型的工具
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class PacketTool {
10 | private PacketTool() {
11 | }
12 |
13 | /**
14 | * 读取到的二进制数据是否是OK包数据
15 | *
16 | * @param buf byte数组
17 | * @return 是否是OK包
18 | */
19 | public static boolean isOkPackete(byte[] buf) {
20 | return (buf[0] & 0xff) == 0;
21 | }
22 |
23 | /**
24 | * 读取到的二进制数据是否是ERR包数据
25 | *
26 | * @param buf byte数组
27 | * @return 是否是ERR包
28 | *
29 | */
30 | public static boolean isErrPackete(byte[] buf) {
31 | return (buf[0] & 0xff) == 0xff;
32 | }
33 |
34 | /**
35 | * 读取到的二进制数据是否是EOF包数据
36 | *
37 | * @param buf byte数组
38 | * @return 是否是EOF包
39 | *
40 | */
41 | public static boolean isEofPacket(byte[] buf) {
42 | return buf.length < 9 && (buf[0] & 0xfe) == 0xfe;
43 | }
44 |
45 | /**
46 | * 读取到的二进制数据中从指定的位置算起是否是EOF包数据
47 | *
48 | * @param buf byte数组
49 | * @param pos 开始位置
50 | * @return 是否是EOF包
51 | */
52 | public static boolean isEofPacket(byte[] buf, int pos) {
53 | return buf.length - pos < 9 && (buf[pos] & 0xfe) == 0xfe;
54 | }
55 |
56 | /**
57 | * 读取到的二进制数据中从指定的位置算起是否是切换权限验证包数据
58 | *
59 | * @param buf byte数组
60 | * @return 是否是切换权限验证包
61 | */
62 | public static boolean isChangeAuthPackete(byte[] buf) {
63 | return (buf[0] & 0xff) == 0xfe;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/tool/PassSecure.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.tool;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.security.MessageDigest;
5 | import java.security.NoSuchAlgorithmException;
6 |
7 | /**
8 | *
9 | * mysql密码加密实现工具
10 | *
11 | * @author hexiufeng
12 | *
13 | */
14 | public class PassSecure {
15 |
16 | private PassSecure() {
17 | }
18 |
19 | /**
20 | * 针对mysql "Secure Password Authentication"方式的实现,mysql支持5中密码验证方式., 其中"Secure Password Authentication"
21 | * 是比较安全的一种,又分为插件支持和非插件支持,我们实现 非插件支持的Authentication::Native41方式.
22 | *
23 | * @see http://dev.mysql.com/doc/
24 | * internals/en/authentication-method.html
25 | * @see
27 | * http://dev.mysql.com/doc/internals/en/secure-password-authentication.html#packet-Authentication::Native41
28 | *
29 | *
30 | * @param password 密码
31 | * @param authRandom 来自mysql server的加密种子
32 | * @return 最终加密后的密码
33 | */
34 | public static byte[] nativeMysqlSecure(String password, byte[] authRandom) {
35 | byte[] passBytes;
36 | try {
37 | passBytes = password.getBytes("utf-8");
38 | } catch (UnsupportedEncodingException e) {
39 | throw new IllegalArgumentException(e);
40 | }
41 |
42 | MessageDigest md;
43 | try {
44 | md = MessageDigest.getInstance("SHA-1");
45 | } catch (NoSuchAlgorithmException e) {
46 | throw new IllegalArgumentException(e);
47 | }
48 |
49 | return scramble411(passBytes, authRandom, md);
50 | }
51 |
52 | /**
53 | * 按照mysql的规范对密码进行加密编码。规则如下:
54 | *
55 | * SHA1( password ) XOR SHA1( "20-bytes random data from server" SHA1( SHA1( password ) ) )
56 | *
57 | *
58 | * 注意:
59 | *
60 | * 本代码实现摘自mysql jdbc驱动的实现
61 | *
62 | *
63 | * @param pass 密码
64 | * @param seed 来在mysql server的动态加密种子,每次连接都不同,由mysql server产出
65 | * @param md sha-1算法实现实例
66 | * @return 加密后的密码
67 | */
68 | private static final byte[] scramble411(byte[] pass, byte[] seed, MessageDigest md) {
69 | byte[] passwordHashStage1 = md.digest(pass);
70 | md.reset();
71 |
72 | byte[] passwordHashStage2 = md.digest(passwordHashStage1);
73 | md.reset();
74 |
75 | md.update(seed);
76 | md.update(passwordHashStage2);
77 |
78 | byte[] toBeXord = md.digest();
79 |
80 | int numToXor = toBeXord.length;
81 |
82 | for (int i = 0; i < numToXor; i++) {
83 | toBeXord[i] = (byte) (toBeXord[i] ^ passwordHashStage1[i]);
84 | }
85 |
86 | return toBeXord;
87 |
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/tool/SafeByteArrayOutputStream.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.tool;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.IOException;
5 |
6 | /**
7 | * 继承{@link ByteArrayOutputStream},输出数据时不抛出异常。
8 | * 用于打包Request
9 | *
10 | * @author hexiufeng
11 | *
12 | */
13 | public class SafeByteArrayOutputStream extends ByteArrayOutputStream {
14 | public SafeByteArrayOutputStream(int size) {
15 | super(size);
16 | }
17 |
18 | /**
19 | * 输出byte数组
20 | *
21 | * @param buff byte数组
22 | */
23 | public void safeWrite(byte[] buff) {
24 | try {
25 | super.write(buff);
26 | } catch (IOException e) {
27 | // ignore
28 | }
29 | }
30 |
31 | /**
32 | * 重新设置某个位置的值
33 | *
34 | * @param pos 指定的位置
35 | * @param value byte数据值
36 | */
37 | public void setPosValue(int pos, byte value) {
38 | super.buf[pos] = value;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriver/unbiz/mysql/lib/protocol/tool/StringTool.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.lib.protocol.tool;
2 |
3 | import java.io.UnsupportedEncodingException;
4 |
5 | /**
6 | * 字符串处理工具
7 | *
8 | * @author hexiufeng
9 | *
10 | */
11 | public class StringTool {
12 | private StringTool() {
13 | }
14 |
15 | /**
16 | * 转换string为utf8 数组,不抛出异常
17 | *
18 | * @param str 要转换的字符串
19 | * @return utf8数组
20 | */
21 | public static byte[] safeConvertString2Bytes(String str) {
22 | try {
23 | return str.getBytes("utf-8");
24 |
25 | } catch (UnsupportedEncodingException e) {
26 | throw new RuntimeException(e);
27 | }
28 | }
29 |
30 | /**
31 | * 把指定的数组转换成string,数组是utf8编码的
32 | *
33 | * @param buff utf8编码的数组
34 | * @return 字符串
35 | */
36 | public static String safeConvertBytes2String(byte[] buff) {
37 | try {
38 | return new String(buff, "utf-8");
39 |
40 | } catch (UnsupportedEncodingException e) {
41 | throw new RuntimeException(e);
42 | }
43 | }
44 |
45 | /**
46 | * 按照指定的字符集转换byte数组为string
47 | *
48 | * @param buff 指定字符集编码的数组
49 | * @param charsetName 字符集
50 | * @return 转换的字符串
51 | */
52 | public static String safeConvertBytes2String(byte[] buff, String charsetName) {
53 | try {
54 | return new String(buff, charsetName);
55 |
56 | } catch (UnsupportedEncodingException e) {
57 | throw new RuntimeException(e);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriverunbiz/mysql/lib/exp/BaseExecuteException.java:
--------------------------------------------------------------------------------
1 | package com.hiriverunbiz.mysql.lib.exp;
2 |
3 | /**
4 | * 与mysql成功连接后,执行交互命令时发生的异常,它只是描述交互异常,但不包括网络异常s。
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class BaseExecuteException extends RuntimeException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | public BaseExecuteException(String message) {
17 | super(message);
18 | }
19 |
20 | public BaseExecuteException(Exception e) {
21 | super(e);
22 | }
23 |
24 | public BaseExecuteException(String message, Exception e) {
25 | super(message, e);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriverunbiz/mysql/lib/exp/HandShakeException.java:
--------------------------------------------------------------------------------
1 | package com.hiriverunbiz.mysql.lib.exp;
2 |
3 | /**
4 | * 与mysql进行连接握手时导致的异常.
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class HandShakeException extends RuntimeException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | public HandShakeException(String message) {
17 | super(message);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriverunbiz/mysql/lib/exp/InvalidMysqlDataException.java:
--------------------------------------------------------------------------------
1 | package com.hiriverunbiz.mysql.lib.exp;
2 |
3 | /**
4 | * 无效的mysql数据异常,一般发生在解析响应数据时。
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class InvalidMysqlDataException extends BaseExecuteException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | public InvalidMysqlDataException(String message) {
17 | super(message);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriverunbiz/mysql/lib/exp/NetworkException.java:
--------------------------------------------------------------------------------
1 | package com.hiriverunbiz.mysql.lib.exp;
2 |
3 | /**
4 | * 底层socket错误,可能网络中断导致
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class NetworkException extends RuntimeException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | public NetworkException(String message) {
17 | super(message);
18 | }
19 |
20 | public NetworkException(Exception e) {
21 | super(e);
22 | }
23 |
24 | public NetworkException(String message, Exception e) {
25 | super(message, e);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriverunbiz/mysql/lib/exp/NotExpectPayloadException.java:
--------------------------------------------------------------------------------
1 | package com.hiriverunbiz.mysql.lib.exp;
2 |
3 | /**
4 | * binlog事件中不合法的有效负载异常
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class NotExpectPayloadException extends BaseExecuteException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | public NotExpectPayloadException(String message) {
17 | super(message);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriverunbiz/mysql/lib/exp/PeerResetNetworkException.java:
--------------------------------------------------------------------------------
1 | package com.hiriverunbiz.mysql.lib.exp;
2 |
3 | /**
4 | * 底层socket被对方关闭异常。
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class PeerResetNetworkException extends BaseExecuteException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | public PeerResetNetworkException(String message) {
17 | super(message);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/main/java/com/hiriverunbiz/mysql/lib/exp/UnOpenedSocket.java:
--------------------------------------------------------------------------------
1 | package com.hiriverunbiz.mysql.lib.exp;
2 |
3 | /**
4 | * socket还没有别打开异常。一般是socket还没有被打开就执行读写操作引起的。
5 | *
6 | * @author hexiufeng
7 | *
8 | */
9 | public class UnOpenedSocket extends RuntimeException {
10 |
11 | /**
12 | *
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | public UnOpenedSocket(String message) {
17 | super(message);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/test/java/com/hiriver/unbiz/msyql/TestNumberUtils.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.msyql;
2 |
3 | import org.junit.Test;
4 |
5 | import com.hiriver.unbiz.mysql.lib.protocol.Position;
6 | import com.hiriver.unbiz.mysql.lib.protocol.datautils.MysqlNumberUtils;
7 |
8 | public class TestNumberUtils {
9 | @Test
10 | public void test3() {
11 | byte[] bin = "123".getBytes();
12 | byte[] buf = { (byte) 0xfe, 0x29 };
13 | Position off = Position.factory();
14 | int value = (int) MysqlNumberUtils.readNInt(buf, off, 2);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/hiriver-modules/mysql-proto/src/test/java/com/hiriver/unbiz/mysql/tool/DecimalTestCase.java:
--------------------------------------------------------------------------------
1 | package com.hiriver.unbiz.mysql.tool;
2 |
3 | import com.hiriver.unbiz.mysql.lib.protocol.tool.MysqlDecimal;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Created by hexiufeng on 2017/5/11.
9 | */
10 | public class DecimalTestCase {
11 | @Test
12 | public void testDecimal(){
13 | int precision=18;
14 | int scale = 4;
15 | byte[] buf = {(byte)0x80,0x0,0x1,0xD,(byte)0xFB,0x38,(byte)0xD2,0x4,(byte)0xD2};
16 | // byte[] buf = {127, -1, -2, -14, 4, -57, 45, -5, 45};
17 | MysqlDecimal myDecimal = new MysqlDecimal(precision,scale);
18 | myDecimal.parse(buf);
19 | System.out.println(myDecimal.toDecimal());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------