-
Notifications
You must be signed in to change notification settings - Fork 2
Home
原文见:实验指导
系统架构如图所示,主要包括两大模块:
- 客户端实例,作为事务的发起者。客户端中的每个线程负责发起事务请求,并将发起的事务请求放到消息队列中,按序发送给服务端具体执行。客户端与服务端实例是全连接的拓扑结构,一般部署在不同的机器上;
- 服务端实例,具体执行事务中的各类操作。不同服务端实例中存有数据,数据使用一致性哈希进行索引,从而形成服务端IP与所存数据的全局分区映射表,通过控制分区映射在测试期间不会修改的方法,保证该映射表是所有节点都可以准确获取的。客户端与服务端实例、服务端与服务端实例间的通信使用TCP/IP协议。每个服务端实例内部可被细分为四个模块:
- 输入消息队列,暂存由客户端/其他服务端发来的消息;
- 执行引擎,分配多个工作线程来对消息队列中的消息进行解析并实际执行,采用一个核绑定一个线程的资源调度方式;
- 并发控制模块,工作线程在执行事务操作的过程中,要维护特定并发控制协议要求的信息,并执行协议规定的流程,从而保证所指定的并发控制协议生效;
- 数据存储模块,负责管理本实例中的数据,将数据都放在内存中。
一个事务的执行流程为:
- 客户端首先发起一个事务请求(由多个操作组成),并将事务放到ClientQueryQueue中。ClientThread会从队列中取出事务请求存入消息队列MsgQueue。之后,消息发送线程会从MsgQueue中取出某一事务的操作集合,封装为一个Request,发送到某一服务端(通过第一个操作所访问的数据确定),作为这个事务的协调节点;
- Request到达服务器后,服务器先对请求进行解析,并把这一事务的所有操作作为一个元素,放到工作队列(TaskQueue)中。工作队列中放置的有来自客户端的新事务和已经开始执行的事务的远程操作,后者在队列中比前者优先级更高。工作线程池中的线程轮询工作队列并处理事务中的操作。当某一工作线程处理当前事务的操作时,其首先对事务进行初始化,然后按顺序执行读写操作,并最终提交或者回滚;
- 执行事务的过程中有两种情况会导致事务进入等待,一是等待某一资源上的排他锁释放;二是需要访问远程服务端中的数据。当远程访问其他服务端中的数据需要的等待时,远程服务端将返回WAIT指令给当前协调节点,协调节点会暂存当前事务的等待状态并调度当前工作线程执行其他事务的操作,从而避免了工作线程的阻塞。当某一等待事务可以继续执行时,基于工作队列的优先级调度策略,它将由第一个可用的工作线程继续执行;
- 并发控制协议所要求的额外操作会嵌入在事务执行过程中,包括读写操作、验证操作、提交/回滚操作等。
- 当协调节点完成某一事务的操作后,他会将事务执行结果放入消息队列,然后由消息发送线程通知客户端当前事务的执行结果。
Linux centos 7.2
需要安装boost-devel和nanomsg
yum install nanomsg, nanomsg-devel, boost, boost-devel,
修改config.h文件的ALGO
参数,选择某种算法进行测试
#define ALGO MVCC
选择要进行的测试类型,修改config.h文件的WORKLOAD
参数,用TEST
跑正确性测试YCSB
跑性能测试
#define WORKLOAD TEST //正确性测试
#define WORKLOAD YCSB //性能测试
在代码根目录下,编译程序进行测试
make deps
make -j 4
# 打开一个终端执行
./rundb -nid0
# 打开另一个终端执行下一句
./runcl -nid1
即可进行测试。
当进行正确性测试时,如果发现输出消息中存在Abort
,则正确性测试通过。
修改config.h文件的如下参数
#define NODE_CNT 1
#define THREAD_CNT 1
#define REM_THREAD_CNT 1
#define SEND_THREAD_CNT 1
#define CLIENT_NODE_CNT 1
#define CLIENT_THREAD_CNT 1
#define CLIENT_REM_THREAD_CNT 1
#define CLIENT_SEND_THREAD_CNT 1
#define WORKLOAD DA //修改为DA测试负载
此外ifconfig.txt文件中,需要写明进行测试的机器ip。例子如下,同学们在148上进行测试时,需要修改ifconfig.txt为如下内容
10.77.110.148
10.77.110.148
同学们在修改完毕上config.h和ifconfig.txt后即可进行测试。 在代码根目录下,编译程序进行测试
make deps
make -j 4
# 打开一个终端执行
./rundb -nid0
# 打开另一个终端执行下一句
./runcl -nid1
该正确性测试负载的输入是input.txt文件,其中是规定好要执行的事务操作序列,将实际的执行序列打印到commit_history.txt文件中。通过对比commit_history.txt和给出的正确执行结果commit_history_2pl.txt/commit_history_occ.txt/commit_history_to.txt进行对比来验证正确性。
在本系统中实现一个并发控制算法,需要实现一套并发控制算法的数据结构和事务操作时的操作接口。 并发控制算法的数据结构可以分为两种:
- 维护在事务中的数据,比如TO算法的开始时间戳。
- 维护在数据项的数据,比如TO算法需要维护数据的写时间戳和读时间戳。
将一个事务分为四个阶段,每个阶段都需要实现一部分接口。
- 事务初始化
- 执行读写操作
- 2PC的prepare阶段
- 2PC的commit阶段。
见txn.h的TxnMgr数据结构,即事务的数据结构。
需要实现row_xxx.h,里面用来存储某个并发控制算法在数据项上维护的信息。可以参考row_occ_template.h
关于读写集 本系统中已经为所有算法提供了读写集的接口,见txn.h文件的Access类:
class Access {
type:操作类型,读操作或者是写操作
orig_row:读写到数据项的原地址
data:读操作时为读取到的值,写操作时为预写入的值
orig_data:读写操作前数据项的原始值,用于事务回滚后的回放。
}
TxnMgr类中也提供了几个函数,用来获取读写集。见178-182行。
access_get_original_row函数:获取读写集中某个操作的数据项原地址
access_get_type:获取读写集中某个操作的类型
access_get_cnt:获取读写集中的总数量
需要实现的内容 事务初始化操作中,需要实现各个并发控制算法数据结构的初始化。比如TO算法需要初始化并获取一个开始时间戳,系统自带的occ_template算法需要初始化事务时间戳范围hash表。
初始化操作所在位置以及修改方法 task_thread.cpp文件里是事务在工作线程中的执行逻辑,其中rtxn_process函数是线程开始执行事务部分的逻辑。 这里需要在第500行之后增加并发控制算法初始化的逻辑,可以参考occ_template算法的写法。
需要实现的内容 事务读写操作中,需要实现获取数据并且进行并发控制处理的接口函数access。 读写操作所在位置以及修改方法 实现读写操作,首先需要实现row_xxx.cpp文件,其中需要实现如下几个接口:
Row_xxx::access(access_t type, TxnMgr * txn); //用于真正执行读写操作,并且进行并发控制操作
之后需要在row.cpp文件中的get_row函数中增加并发控制算法的读写操作。可以参考occ_template算法的实现:
- 初始化row结构体,用来存储数据库中读写到的数据(图中红框)
- 实现row_xxx.cpp以及其中的access接口,真正执行对数据的读写和并发控制处理,比如2PL的加锁,TO算法的时间验证等等(图中黄框)
- 将access函数中获取的数据copy到row结构中输出。(图中蓝框)
需要实现的内容 实现OCC等含有验证操作的算法时,需要额外实现事务验证的逻辑。 验证所在位置以及修改方法 事务验证的入口见下图,在txn.cpp:467行
在validate
函数中,需要参考occ_template(红框)的算法实现OCC的验证方法。图中黄框是occ_template的验证接口函数。
这里推荐实现occ.cpp和occ.h两个文件用来处理全局的OCC验证。
需要实现的内容 这里需要实现事务的提交和回滚两种接口。 每种接口都需要实现两个部分:提交或回滚数据项,以及对事物数据结构的清理。 读写操作所在位置以及修改方法 事务提交或回滚的函数入口见下图
在row.cpp的return_row
函数中,实现对应的提交/回滚数据项操作。
可以参考系统自带的occ_template算法
这里推荐在row_xxx.cpp中实现commit
和abort
两种接口:
Row_xxx::commit(access_t type, TxnMgr * txn, RowData * data);
Row_xxx::abort(access_t type, TxnMgr * txn);
需要在上图的commit
和abort
函数中完成清理并发控制算法某些数据结构的工作。
例如occ_template算法在413行完成了对事物时间戳范围的清理。
以及abort
函数中的445行
代码最新提交中已经增加了MVCC的接口,可以参考新添加的row_mvcc.h和row_mvcc.cpp。接口的具体介绍见row_mvcc.h的注释。