承接前一篇, 服务器采用C编写, 逻辑层使用LUA, 搭配开源mongodb c driver开发异步查询接口.
有了上一次的改造, 这次来说说是如何使用改造后的接口实现异步查询.
首先, 再来理清一下思路, 现在的一次完整同步查询被拆分成3个步骤:
1.创建并发送请求
2.接受返回结果消息头
3.接受返回结果数据并做相应的回调处理
为此我们需要2个结构来处理这个过程:
上图的第一个结构为网络连接内部参数, 用于每次回调处理recv的时候取数据.
第二个结构为hash表中的数据, 用每次异步请求ID作为KEY.
下面会分别对这三个阶段进行讲解:
请求发送:
ok, 请求发送时, 首先我们需要为该次异步请求生成一个query id, 该id可以采用例如UUID类的方法生成, 也可以简单的使用自增ID.
其次, 填充本次请求内容, 并将数据库操作对象保存至hashtbl(query id作key), 将请求发送给DB.
最后, 将query id返回给LUA逻辑层, 挂起当前coroutine.
C 接口如下:
LUA 层接口:
接收并处理响应:
这里面共包含2个部分, 处理消息头和处理消息数据并打包至逻辑层.
为什么这里面要把解析头部和处理数据部分分开, 是因为头部长度固定, 我们可以一次读取完成, 但是后续的数据长度是从头部信息中获取
得到的, 我们没办法在一开始就确定一共要读多长的数据, 故要分开处理.
解析头部:
固定读取定长消息头, 得到后续数据长度和query id 并得到mongo_reply, 我们需要保存该mongo_reply以便后续处理.
这里面我们再次用到了query id, 用其将mongo_reply保存至请求时的hash结构指定KEY中.
处理数据:
此时由于本次接受到的数据并非一定满足后续数据长度, 故有可能中断, 但是好在该次响应在网络层面上数据是连贯的, 所以我们在读取
完整响应期间, 可以利用网络框架帮助我们保存一些临时参数, 比如保存query id, 这样即使在非连贯的读取一次响应数据时也不会因为
获取query id而产生不必要的麻烦.
这样当我们读取完整数据后, 就可以封装结果至逻辑层使用了 :)
接受逻辑:
在处理数据时, 再次从hashtbl中获取了"ns", 写到这里, 大家应该明白了为什么使用一个hashtbl来保存这个ns, 而不是直接放在网络框架中
做临时参数处理, 因为每次异步请求都会得到ns, 但我们又不能保证每次都是一样, 请求和响应并非连贯导致了临时保存的结果可能是错误的也
可能是刚刚被置空了...
封装结果至LUA逻辑层, 这里就不列举代码了, 简单说下, 就是将结果保存为一维线性, 二维hash的lua table中.
然后调用逻辑层唤醒指定query id的coroutine继续执行.
总结:
至此, 一个完整的异步查询请求就编写完成, 由于时间关系, 代码层面上还有很多可以精简优化的余地, 我在此仅仅作为提供思路, 欢迎一同探讨 :)
email : hyzwowtools@163.com