chunjun icon indicating copy to clipboard operation
chunjun copied to clipboard

[Bug] [com/dtstack/chunjun/connector/oraclelogminer/listener/LogMinerConnection.java] 缓存过期,无法找到undoLog,实际存在

Open CarlosShao2 opened this issue 2 years ago • 6 comments

Search before asking

  • [X] I had searched in the issues and found no similar issues.

What happened

com/dtstack/chunjun/connector/oraclelogminer/listener/LogMinerConnection.java 该类的 public boolean hasNext(BigInteger endScn, String endRowid)方法中的一段代码逻辑有问题。 if (endScn != null && rowId != null) { if (scn.compareTo(endScn) > 0) { return false; } if (scn.compareTo(endScn) == 0 && rowId.equals(endRowid)) { return false; } }

首先同一事务下,scn和rowid并不是唯一id,不能用于边界筛选。在执行rollback逻辑的时候,如果TransactionManager的缓存失效,会导致undolog永远也无法找到!因为原逻辑是在递归查找的时候看到scn和rowid相等就返回,但这条数据并不是earliestResolveOperateForRollback上次用于回滚的记录(同一条记录在一个事务内被修改了多次回滚了多次)。

What you expected to happen

zz

How to reproduce

v$logmnr_contents是否有字段是递增不重复的?如果用,才能解决这个问题,但是对这玩意也不太熟,网上查了rs_id貌似满足这个条件

Anything else

No response

Version

master

Are you willing to submit PR?

  • [X] Yes I am willing to submit a PR!

Code of Conduct

CarlosShao2 avatar Aug 14 '23 08:08 CarlosShao2

rs_id在一个事务里是唯一的,但是在不同的事务里有可能是不唯一的,也许可以通过事务id +rs_id,来确定一条数据。 scn和rowid的确不能唯一确定,但是唯一的情况很少,当时做这一部分,没找到可以唯一确定的键,所以使用scn和rowid来暂时作为边界处理

这的确是一个bug,如果你有兴趣可以尝试提供一个pr解决,基于事务id +rs_id 来作为唯一键来处理

yanghuaiGit avatar Aug 14 '23 11:08 yanghuaiGit

事实上即使通过事务id +rs_id确定一条数据,也无法解决如何查找回滚数据对应的undolog,假设同一事务里对同一条数据做了多次操作进行回滚,如何将回滚事务数据和前面哪次操作进行匹配

scn和rowid在非回滚数据中是可以确定的,因为scn相等是因为同一事务做了批量操作,这一批影响数据的scn相等,但是无法批量对同一数据操作,而rowid是可以确定一条数据的,因此scn和rowid是可以确定一个事务中非回滚数据的位置。 因此递归查找回滚事务对应的undolog,根据scn和rowid是可以找到的 可能需要你的具体场景分析下: 如果读取第一条回滚事务数据时,transactionmanager失效,会递归加载文件查询 因为回滚数据的scn是相等的,所以根据回滚数据的scn作为边界,能查找到所有小于此scn下的所有非回滚数据,再取最近一条非回滚数据即为第一条回滚数据对应的undolog,这样递归查询,直到transactionmanager里的数据全部查完后,继续以上一次非回滚数据的scn和rowid是可以作为截止位置的。

所以如果是递归查询回滚数据理论上是没问题的,scn作为checkPoint是有问题的,因为scn号是可以重复的,应该是事务id和rs_id来确定恢复的位点。但如果事务id和rs_id作为起点,递归查找undoLog的逻辑可能需要修改,需要记录一个当前回滚数据在所有回滚数据的index顺序,然后加载最近的非回滚数据,从后往前index位置数据就是undolog

yanghuaiGit avatar Aug 14 '23 13:08 yanghuaiGit

递归查询非回滚数据的scn和rowid,只有第一次加载回滚数据时,transactionmanager里没有缓存,这个时候就会以第一条回滚数据的scn和rowid作为截止条件,查找非回滚数据,后续的每次递归查询数据的rowid和scn都是非回滚数据的rowid和scn,这个理论上在非回滚数据里是可以作为边界的

yanghuaiGit avatar Aug 14 '23 13:08 yanghuaiGit

我的想法是这样的(以下情况均为缓存失效处理回滚记录的情况): 1.如果根据当前事务id从earliestResolveOperateForRollback中可以获取到上次最近的操作,就以最近的操作对应的非回滚记录的rs_id+scn为边界,找到上一个该事务非回滚的记录,那就找到了当前回滚记录对应的非回滚记录的undo_sql。 2.如果连earliestResolveOperateForRollback在该事务id下都是空的,就比较麻烦了。因为不知道当前scn的前面是否还有回滚记录,就无法将回滚和非回滚对应起来,那就得去找前面的所有(也不是所有,找到需要的回滚记录就返回即可)的非回滚和回滚的记录,然后就跟消消乐一样,回滚记录入栈遇到非回滚记录出栈,直到需要处理的回滚记录出栈了,就找到属于自己的非回滚记录的undo_sql;

CarlosShao2 avatar Aug 15 '23 09:08 CarlosShao2

1692092957717

就比如这个事务,我的起始scn设置成1211748,项目也会有bug,应该找35行,实际找到了36行,应该先消消乐一波。

CarlosShao2 avatar Aug 15 '23 09:08 CarlosShao2

是的,查找回滚数据应该是按照从最后一个回滚数据数据行开始往前消消乐,直到和当前非回滚数据在整个非回滚数据的index

yanghuaiGit avatar Aug 28 '23 02:08 yanghuaiGit