Operational Transformation算法解决的问题是如何merge基于相同的状态产生的不同的操作序列。如下图所示,从上往下看,基于相同的起点,左右有两个操作OP1和OP2.为了merge两个操作为一体,我们可以从两个方向入手,一个方向是从OP1入手,在执行完OP1后,执行OP2;另一个方向是从OP2入手,在执行完OP2后,执行OP1.但是,简单的将操作执行,并不正确,以OP1为例,在执行完OP1后,数据的状态发生了变化,而OP2是基于初始的状态,所以不能直接执行OP2,而需要将操作做一个变换,以OT(OPA,OPB)作为记号。使用OT算法后,必须保证,左边的执行序列OP1,OT(OP2,OP1)执行后的结果,与右边的执行序列OP2,OT(OP1,OP2)执行后的结果相同。
上图是对一个【元操作】的定义。真是的场景中,左边和右边不可能仅仅有一个操作,而是有多个操作。我们先考虑左边有两个操作,右边只有一个操作。如下图所示。
OP1和OP3最先merge。图中到达中轴线的节点。之后,需要将OP2merge进去,必须执行OT(OP2,OP3‘)== OT(OP2, OT(OP3, OP1))
再考虑左边有三个操作,右边只有一个操作。如下图所示。
按照左上-右下的辅助线,把merge过程切割成若干步骤。第一步是在右操作为OP4时mergeOP1,第二步是在右操作为OP4‘时mergeOP2.第三步是在右操作为OP4‘’时mergeOP3。以此类推,可以将merge【左N右1】过程理解成一个递归算法。
上文求解的是左边有若干操作,右边只有一个操作的情形。我们继续扩展,考虑左边有若干操作,右边也有若干操作的情形。如下图所示。
按照右上-左下的辅助线,我们可以将这种求解分割成若干步骤的merge【左N右1】。第一步,左N指的是OP1,OP2,右1指的是OP3.第二步,左N指的是OP1‘,OP2’,右1指的是OP4.以此类推,我们可以将merge【左N右M】的过程理解成一个递归算法。
至此为止,我们将最通用的merge【左N右M】的算法一步步分解下来。下面,我们再考虑一个基本问题,OT(OPA,OPB)指的是基于OPB,对OPA做转换,转换的结果是OPA‘。如果转换的结果不是一个操作OPA’,而是一个操作序列「OPA1,OPA2……」呢?如下图所示。
OT(OP4,OP1)的结果是「OP41,OP42」。求解步骤,首先是求解出OP1‘,将问题缩小为左边「OP2,OP3」,右边为「OP41,OP42」。然后将问题抽象为【左2右2】,先求解【左2右1】,得到「OP2’,OP3‘」;然后将问题缩小为【左2右1】,左为「OP2‘,OP3’」,右为OP42.最终求出结果。
现在,我们分析了所有的问题种类。我们可以分析一个具体问题。
在真实场景中,操作OPA和操作OPB可能是互斥的。因此,OT算法往往是biased OT,即以某一个方向为倾向,假设我们的OT是向右方向biased,为了保证对于互斥的操作,OT算法的正确性,我们可以定义如图所示的【元操作】。
因为现在的OT是向右方向倾斜的,所以对于互斥的操作,OP2更优先,所以,只能将OP1变换成空操作(null),而OT(OP2,OP1)必须撤销OP1的影响,并施加OP2的影响。所以我们引入Reverse()操作,即求一个操作的逆操作。
在merge【左N右M】的情形下,出现互斥的情况,就可以使用上述的元操作进行解决。
行文至此,我们通过引入Reverse()操作,解决了互斥操作的OT问题。我们继续加以引申,既然我们接受并引入了Reverse()操作,OT算法本身就变得足够灵活,可以应对更复杂的操作对的OT.考虑操作OPA和OPB。有属性如下:若OPA已执行,则OPB不可执行;若OPB已执行,则OPA可执行。正常的OT示意图如下图所示:
显然,该OT组合是错误的。为了使OT组合正确,我们可以使用Reverse()功能。
如图所示,我们可以发现,只要求出了右方向的OPA’,那么我们就可以通过Reverse()操作和该OPA',组合成操作序列{Reverse(OPA), OPB, OPA'},该序列就是左方向的OT(OPB, OPA)的结果.
将该结论推广开,我们完全只需要提供单个方向的OT变换方法,就可以自动得到另一个方向的OT变换方法。但是,代价也是高昂的,那就是,普通的OT变换结果还是一个操作,而上述方法的结果是三个操作,导致performance会有成倍的下降。实践中,这种tradeoff往往发生在某个OT方法过于复杂时。