首先声明,本人不接受任何因本回答的追责。如您不同意本条款,请当没看见下面的内容。由于txc-client-2.0.2.3.jar 使用的混淆技术,所以打开就是这个样子。
通过点开 com.a.a.a.b.a.a 类可以发现
基本上可以断定 ,com.a.a.a xxx 包下是一些sql解析的代码。由于他提供的dome 中有个 tx_undo_log 表的建表语句 所以,通过搜索发现了
这个类处理后 信息为[
["0001", "diamond.getconfig 执行错误", "检查与diamond的连接"],
["0002", "在diamond 中获取的数据库key为空", "检查diamond上的数据"],
["0003", "在diamond 中取出取出的group信息为空", "检查diamond上的数据"],
["0004", "netty线程池满", "请在配置文件中调整线程数, corePoolSize 的值调大一些"],
["0005", "mt模式资源管理器未定义", ""],
["0006", "bean name为%s的实例未在spring上下文中定义", ""],
["0007", "diamond 写入错误,mt服务中止", ""],
["0101", "无法连接服务器", "请检查txc server是否启动,到txc server的网络连接是否正常"],
["0102", "register client app name failed", "请检查txc server是否启动,到txc server的网络连接是否正常"],
["0103", "txcConnection closed", "网络断开,请检查到对端(client 或txc server)的网络连接"],
["0104", "dispatch 错误", "网络处理错误,请检查到对端(client 或txc server)的网络连接 "],
["0105", "on message 错误", "网络处理错误,请检查到对端(client 或txc server)的网络连接 "],
["0201", "表 txc_undo_log 不存在", "检查txc server连接数据库的表结构"],
["0202", "sql 类型错误,应为 delete update insert 之一", "sql语句不支持,请修改"],
["0203", "数据库表不存在", "请检查数据库表"],
["0204", "同步真实表错误", "请查看表结构是否修改"],
["0205", "获取表Meta失败", "请检查数据库表"],
["0206", "DRDS全局提交失败", "请检查数据库表"],
["0207", "DRDS全局回滚失败", "请检查数据库表"],
["0301", "sleep 时出错", ""],
["0302", "创建随机数失败", ""],
["0303", "client 未注册appname", ""],
["0304", "注册RM失败", ""],
["0305", "sql cache 出错", ""],
["0306", "事物检查错误", ""],
["0307", "开启rt分支错误", ""],
["0308", "处理分支回滚错误", ""],
["0309", "处理分支提交错误", ""],
["0310", "删除分支日志错误", ""],
["0311", "插入分支日志错误", ""],
["0312", "更新分支日志错误", ""],
["0313", "获取分支日志错误", ""],
["0314", "分支回滚逻辑错误", ""],
["0315", "更新全局日志错误", ""],
["0316", "同步全局回滚错误", ""],
["0317", "删除全局日志错误", ""],
["0318", "异常", ""],
["0319", "server 发送请求失败", ""],
["0320", "server发送响应错误", ""],
["0321", "插入全局日志错误", ""],
["0322", "转储TXC事务日志错误", ""],
["0323", "主备节点同步错误", ""],
["0324", "报警日志错误", ""],
["0325", "诊断性错误", ""],
["0326", "查询读锁错误", ""],
["0327", "保存高警日志错误", ""],
["0328", "写TXC日志错误", "请排查SQL"],
["0401", "Txc切换分组失败", "请检查diamond"],
["0501", "Txc Insert 解析主键错误", "请检查SQL"],
["9999", "未预期异常", ""],
["10000", "unknown error", ""]
]
//涉及到的表 TXC_MT_JOURNEL txc_undo_log
所以认定 在事务回滚过程中 有用到txc_undo_log然后再 com.taobao.txc.resourcemanager.a.e 类中 发现了对于 txc_undo_log 的方法,虽然
表名被当成参数传人 ,在静态块中初始化 ,此处有疑问,为什么这么做呢,是考虑到以后会改表名么? 果然 阿里就是叼 static {
a = LoggerInit.logger;
e.b = "txc_undo_log";
e.c = 0;
}
com.taobao.txc.resourcemanager.b.b 类中也有类似的代码
猜测txc_undo_log 应该是在 参与事务的所有库中都有这张表然后我在 com.taobao.txc.common.c.F 类下发现了如下代码
感觉非常像平常写 rpc调用时 用于反序列化的,的类映射,所以就,一个个点开来看,处理到了如下信息, 感谢写代码的童鞋,重载了toString 方法啊 ,有两个类没重载我就 没法子了//com.taobao.txc.common.c.F 包下内容
1 : "BeginMessage timeout:" + "this.a" + " appname:" +" this.b "+ " txcInst:" +" this.c";
2 : "BeginResultMessage result:" +" this.a "+ " xid:" + "this.c";
3 : "BranchCommitMessage " +" sb.append(",size:").append(this.b.size()).append(" DBname:").append(this.e).append(",appName:").append(this.d).append(",commitMode:").append(this.g).append(",udata:").append(this.h).append(",rtsql:").append(this.f).toString();"
4 : "BranchCommitResultMessage" + ;
5 : "BranchRollbackMessage" + "DBname:" + this.e + ",appName:" + this.d + ",commitMode:" + this.f + ",isDelLock:" + this.g + ",udata:" + this.h;
6 : "BranchRollbackResultMessage" + "result:" + this.a;
7 : "GlobalCommitMessage tranId:" + "this.a";
8 : "GlobalCommitResultMessage tranId:" + this.c + ",result:" + this.a + ",msg:" + this.b();
9 : "GlobalRollbackMessage tranId:" + this.a;;
10 : "GlobalRollbackResultMessage tranId:" + this.c + ",result:" + this.a + ",msg:" + this.b();;
11 : "RegisterMessage key:" + this.b + " tranId:" + this.a + " Commit mode:" + this.d + " business key:" + this.c;;
12 : "RegisterResultMessage result:" + this.a + ",tranId:" + this.c + ",branchId:" + this.d;
13 : "ReportStatusMessage this.a + :" + this.b + " ReportStatusMessage:" + this.c + ",key:" + this.d;
14 : "ReportStatusResultMessage branchId:" + this.c + ",result:" + this.a;
15 : "BeginRetryBranchMessage dbName:" + this.b + ",Commit mode:" + this.c + ",effectiveTime:" + this.a + ",sql:" + this.d;
16 : "BeginRetryBranchResultMessage result:" + this.a + ",xid:" + this.c + ",branchId:" + this.d
17 : "ReportUdataMessage " +this.a + ":" + this.b + " ReportUdataMessage udata:" + this.d;
18 : "ReportUdataResultMessage result:" + this.a;
19 : "TxcMergeMessage "
20 : "TxcMergeResultMessage ";
21 : "QueryLockMessage tranId:" + this.a + ",key:" + this.b + ",business key:" + this.c;
22 : "QueryLockResultMessage result:" + this.a + ",message:" + this.b();
101 : "com.taobao.txc.rpc.impl.RegisterClientAppNameMessage");
102 : "com.taobao.txc.rpc.impl.RegisterClientAppNameResultMessage");
103 : "com.taobao.txc.rpc.impl.RegisterRmMessage");
104 : "com.taobao.txc.rpc.impl.RegisterRmResultMessage");
105 : "com.taobao.txc.cluster.message.RegisterClusterNodeMessage");
106 : "com.taobao.txc.cluster.message.RegisterClusterNodeResultMessage");
107 : "com.taobao.txc.cluster.message.ClusterBranchMessage");
108 : "com.taobao.txc.cluster.message.ClusterBranchResultMessage");
109 : "com.taobao.txc.cluster.message.ClusterGlobalMessage");
110 : "com.taobao.txc.cluster.message.ClusterGlobalResultMessage");
111 : "com.taobao.txc.cluster.message.ClusterSyncMessage");
112 : "com.taobao.txc.cluster.message.ClusterSyncResultMessage");
113 : "com.taobao.txc.message.ClusterDumpMessage");
114 : "com.taobao.txc.message.ClusterDumpResultMessage");
115 : "com.taobao.txc.cluster.message.ClusterMergeMessage");
116 : "com.taobao.txc.cluster.message.ClusterMergeResultMessage");
117 : "com.taobao.txc.cluster.message.ClusterQueryLockMessage");
118 : "com.taobao.txc.cluster.message.ClusterQueryLockResultMessage");
119 : "com.taobao.txc.cluster.message.ClusterAlarmMessage");
120 : "com.taobao.txc.cluster.message.ClusterAlarmResultMessage");
121 : com.taobao.txc.common.c.t;
122 : com.taobao.txc.common.c.u;
123 : "com.taobao.txc.cluster.message.ClusterBkupMessage");
124 : "com.taobao.txc.cluster.message.ClusterBkupResultMessage");
由此然后 通过调用其中一些类的构造方法,发现是在 netty 的hander 里面进行的创建,所以我觉得 这里应该是实现了一个小型 netty的 rpc调用 服务有如下代码package com.taobao.txc.client;
import java.util.*;
import java.util.concurrent.*;
import com.taobao.txc.a.b.*;
import com.taobao.txc.common.a.*;
import com.taobao.txc.a.a.*;
import com.taobao.txc.resourcemanager.a.*;
import com.taobao.txc.resourcemanager.a.a.*;
import com.taobao.txc.resourcemanager.*;
import com.taobao.txc.resourcemanager.mt.*;
import com.taobao.txc.common.*;
public class a
{
private static final LoggerWrap b;
private static a c;
private String d;
private String e;
private com.taobao.txc.client.a.a f;
public final ThreadPoolExecutor a;
public static a a(final String s, final String s2, final int n, final Set<
String> set, final String s3, final String s4, final int n2) {
if (a.c == null) {
synchronized (a.class) {
if (a.c == null) {
a.c = new a(s, s2, n, set, s3, s4, n2);
}
}
}
return a.c;
}
private a(String property, String property2, int int1, final Set<
String> set, final String d, final String e, final int n) {
this.f = null;
this.a = new ThreadPoolExecutor(32, 200, 500L, TimeUnit.SECONDS, new LinkedBlockingQueue<
Runnable>(20000), new ThreadPoolExecutor.CallerRunsPolicy());
if (System.getProperty("txc.appname") != null) {
property = System.getProperty("txc.appname");
}
if (System.getProperty("txc.servergroup") != null) {
property2 = System.getProperty("txc.servergroup");
}
if (System.getProperty("txc.mode") != null) {
int1 = Integer.parseInt(System.getProperty("txc.mode"));
}
this.d = d;
this.e = e;
this.a(property, property2, int1, set, n);
}
public void a(final String s, final String s2, final int n, final Set<
String> set, final int n2) {
System.out.println("client mode:" + n + " [1:AT 2:MT 3:AT&MT 4:RT 5:AT&RT 6:MT&RT 7:AT&MT&RT]");
System.out.println("txcAppName:" + s);
System.out.println("txcServerGroup:" + s2);
final g b = g.b(this.a);
b.g(s2);
b.a(s);
b.a(n2);
b.a(set);
b.e(this.a());
b.f(this.b());
b.b();
o.a(s2);
com.taobao.txc.client.a.b.info("RpcClient inited. client mode:" + n + " txcAppName:" + s + " txcServerGroup:" + s2);
final com.taobao.txc.client.a.a.a c = com.taobao.txc.client.a.a.a.c();
c.a(b);
c.d();
this.f = c;
com.taobao.txc.client.a.b.info("TxcTransactionManager inited");
i i = null;
if ((0x1 & n) > 0) {
final c a = com.taobao.txc.resourcemanager.c.a(this.a);
a.c(s);
a.b();
com.taobao.txc.client.a.b.info("RmRpcClient inited");
final j c2 = j.c();
c2.a(a);
c2.a(new e());
c2.d();
com.taobao.txc.client.a.b.info("TxcResourceManager inited");
i = new i();
i.a(a);
i.a(c2);
i.a();
com.taobao.txc.client.a.b.info("AT TxcRMMessageListener inited");
}
if ((0x2 & n) > 0) {
final com.taobao.txc.resourcemanager.mt.c b2 = com.taobao.txc.resourcemanager.mt.c.b(this.a);
b2.c(s);
b2.b();
com.taobao.txc.client.a.b.info("MtRmRpcClient inited");
final MtResourceManager txcResourceManager = MtResourceManager.getTxcResourceManager();
txcResourceManager.a(b2);
txcResourceManager.c();
com.taobao.txc.client.a.b.info("MtResourceManager inited");
if (i == null) {
i = new i();
}
i.b(b2);
i.a(txcResourceManager);
i.a();
com.taobao.txc.client.a.b.info("MT TxcRMMessageListener inited");
}
if ((0x4 & n) > 0) {
final com.taobao.txc.resourcemanager.d.b a2 = com.taobao.txc.resourcemanager.d.b.a(this.a);
a2.g(s2);
a2.a(s);
a2.b();
com.taobao.txc.client.a.b.info("RtRpcClient inited");
final com.taobao.txc.resourcemanager.d.a h = com.taobao.txc.resourcemanager.d.a.h();
h.a(a2);
h.d();
com.taobao.txc.client.a.b.info("RtResourceManager inited");
if (i == null) {
i = new i();
}
i.a(a2);
i.a(h);
i.a();
com.taobao.txc.client.a.b.info("RT TxcRMMessageListener inited");
}
}
public String a() {
if (this.d == null || this.d.isEmpty()) {
this.d = System.getProperty("txc.accesskey");
}
return this.d;
}
public String b() {
if (this.e == null || this.e.isEmpty()) {
this.e = System.getProperty("txc.secretkey");
}
return this.e;
}
static {
b = LoggerInit.logger;
a.c = null;
}
}
com.taobao.txc.common.TxcContext 类中是存储了一些事务上下文的东西
TxcTable 感觉是存储了些 ddl 语句的影响行数据。用于做 提交不一致的回滚package com.taobao.txc.resourcemanager.a.d;
import com.taobao.txc.resourcemanager.b.a.*;
import com.taobao.txc.parser.a.b.a.*;
import java.sql.*;
import com.taobao.txc.parser.struct.*;
public class c<
T> extends a<
T>
{
public c(final com.taobao.txc.resourcemanager.b.a.a a, final d d, final com.taobao.txc.resourcemanager.b.b.a.a<
T> a2, final com.taobao.txc.parser.a.b.a.b b) {
super(a, d, a2, b);
com.taobao.txc.resourcemanager.a.b.a(b, a, d);
}
@Override
public T b(final Object... array) {
final com.taobao.txc.parser.a.b.a.b c = this.c();
final com.taobao.txc.resourcemanager.b.a.a a = this.a();
final d b = this.b();
final com.taobao.txc.resourcemanager.b.b.a.a<
T> d = this.d();
T t = d.b(0);
final Statement c2 = b.c();
final TxcRuntimeContext a2 = a.a((String)null);
a.setAutoCommit(false);
try {
final String string = c.d() + c.a(c2) + " FOR UPDATE";
c.b(c.a(b, string));
t = d.b(c2, array);
c.c(c.b(b, string));
a2.a(c);
a.commit();
}
catch (Throwable t2) {
a.rollback();
throw new SQLException(t2);
}
finally {
a.setAutoCommit(true);
}
return t;
}
@Override
public T c(final Object... array) {
final com.taobao.txc.parser.a.b.a.b c = this.c();
final com.taobao.txc.resourcemanager.b.a.a a = this.a();
final d b = this.b();
final com.taobao.txc.resourcemanager.b.b.a.a<
T> d = this.d();
d.b(0);
final Statement c2 = b.c();
final TxcRuntimeContext c3 = a.c();
T b2;
try {
final String string = c.d() + c.a(c2) + " FOR UPDATE";
c.b(c.a(b, string));
b2 = d.b(c2, array);
c.c(c.b(b, string));
c3.a(c);
}
catch (Throwable t) {
throw new SQLException(t);
}
return b2;
}
}
此类 使用了 FOR UPDATE 语句,感觉是作为提交阶段,先提交者 锁住此此事务更改的参与表,防止 被其他事务改写的情况。好了,后续我还会回答一个 该事务中间件的实现猜想,希望抛砖引玉,能借助大家的力量弄懂该组件。--------------------------------------------------------------------------------------------------------------下面是我的猜想----------------------------------------------------所以我的大致猜想是这样的,如果不对欢迎拍砖1. TXC 是基于 rocketmq ,Netty 来实现的。2. 实现了一个 以rocketmq 和 操作库 的 tx_undo_log 做日志存储 ,Netty RPC 做,事务控制的 二阶段提交协议。3. 在事务提交阶段,会同时开启一个事务,锁住 分布式事务的参与记录,等待事务合并后释放。或者有节点提交错误时回滚。一个事务的处理流程我认为可能是这样的1. 启动之后 启动RPC 连接上事务控制服务2. 包装了 DataSource ,和 jdbc 的 Connection ,在进行 DML 操作之前,先使用 解析到对应表的 ,使用 SELECT xxx from xx for update 语句 构造 undo 语句。操作完了后,发送一个消息,通知事务控制服务,可以本事务可以提交了。3. 判断自己外部 是否还有事务(即是自己是不是最外层事务)。如果自己不是最外层事务,则返回(不阻塞线程), 如果自己是最外层事务,则 等待事务 提交(当前线程阻塞).4. (另外的线程)Rpc 接受到 事务控制器 提交事务命令后。获取合并事务。如果成功(柱塞住参与事务的表记录),回复成功消息,失败回复失败消息(回滚,不再锁住表记录)。 5. 根据事务提交情况,控制器会 下发,完成事务,或者回滚事务的命令,由RPC线程处理, 如果成功则释放,锁住的表记录,事务完成, 最外层业务线程的阻塞返回结束,如果失败,则执行 uodo 日志里面的sql ,回滚操作,释放表记录, 最外层业务线程阻塞返回抛出 事务异常。现在没想明白的问题:1. 在事务提交阶段,提交后表记录,的锁已经释放,怎么样才能保证该行数据能被后续的锁操作锁住,业务在大量事务操作的时候,可能记录先被其他的事务抢到了。我把我的猜想跟我同事说了后他觉得这个 做法有点像 ebay经典的BASE (basically available, soft state, eventually consistent)方案希望各位大神能提出看法附上 客户端jar包下载地址http://txc-console.oss-cn-beijing.aliyuncs.com/sdk/txc-client-2.0.18.jar?spm=5176.doc43161.2.2.mIkVrs&file=txc-client-2.0.18.jar
谈起麻将本人喜欢血战棋牌问答,由于经常混血摸岛屿.. 渐渐形成贪大的心理,今年之前我普嘛5000以上还没有一次冠军就是混用了太多血战的打法 喜欢贪,最让我记忆深刻的一副牌 起手三混 上一张听7对 上家点一万(没理由胡 三混不自摸多浪费) 结果上家一碰 听了 …我接着打一万 棋牌问答,第二张九条 点炮 郁闷…很遗憾你的基数不足………那时候就决定要改变自己普麻的打法..之后也拿了不少冠军。说起普麻我很欣赏至尊皇冠Cal囝vin 的打法 ,他让我明白普麻不点炮才是真理。