OT算法-前端锁的解决方案

(operational-transformations)
此篇文章写给一同在进行ot算法实践中的朋友们,希望抛砖引玉,有对ot算法感兴趣的小伙伴可以联系我一下,目前关于此算法的一些细节处理上我还有一点点的疑惑部分,希望能讨论解决

巨人的肩膀

我们可以先看一下其他人是如何解决的:

前端状态图

前端状态图

Purpose 目的

OT算法解决协同编辑问题在在落地中客户端设计可以简化为三种状态和三个方法

如何解决

数据结构设计如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
client {
version //记录当前版本
state //记录当前状态
}

//三种状态
Synchronized {
}

AwaitingConfirm {
hassendop //记录已经发送的op操作
}

AwaitingWithBuffer {
hassendop //记录已经发送的op操作
needsendop //记录需要发送的op操作
}

Synchronized状态:当前客户端已同步服务器状态 AwaitingConfirm状态:当前客户端向服务器发送了op操作命令,还没有收到确认消息 AwaitingWithBuffer:当前客户端向服务器发送了op操作,还没有收到确认消息,且客户端有进行了新的操作

每种状态下均有可执行三种操作applyclient、serverack、applyserver,下面分别说明每种状态下各种操作的具体含义

Synchronized状态 applyclient:向服务器发送op操作命令,并设置client状态为AwaitingConfirm serverack:无 applyserver:收到服务器op操作指令,执行服务器op操作指令,版本号加1

AwaitingConfirm状态 applyclient: 缓存客户端新的op操作命令,并设置client状态为AwaitingWithBuffer serverack: 设置客户端状态为Synchronized,版本号加1 applyserver: 客户端执行OT变换后的服务端op操作,对hassendop进行OT变换,状态保持不变,版本号加1

AwaitingWithBuffer状态 applyclient: 缓存合并客户端新的op操作指令,状态不变 serverack: 发送缓存的客户端新指令,设置状态为AwaitingConfirm,版本号加1 applyserver: 客户端执行OT变换后的服务端op操作,对hassendop进行OT变换,对needsendop进行OT变换,版本号加1

细化方案

1
2
3
4
5
6
7
8
// 外部缓存区(外部缓存区收到锁的影响,锁上即进入缓存区,解锁循环取出缓冲区)
var outBuffer = new Array();
// 缓存区锁(0为未锁,1为锁)(此处锁上了所有操作都暂时进入缓存区,直至解锁)
let bufferlock = 0;
// 缓存区锁之前发送的对象(用于发送过来的数据与缓存区进行对比,以便解开缓存区锁)
let sendBuffer = null;
// 传递出去的对象 (兼并缓存区)(如果没有任何消息进入解锁的话,所有文字操作都暂时存在缓存区内)
let buildParameters = "";

如上所示,我增加了锁状态的方式作为了前端状态的开关,在锁未解开的情况下,所有操作存入缓冲区,当锁解开的情况,开始输出缓冲区信息(实际上是开始解决版本冲突)

总结

实际上在实际代码中,由于解决的问题颇多,整篇文章的是归纳整理后的,实际代码更为复杂,记录原理即可了