最近在选用NOSQL数据库的时候最终选择了mongodb, 感觉其各方面都很优秀, 于是为服务器增加了一组mongodb的接口, 以方便LUA逻辑层使用.
驱动方面选用了官方指定的C DRIVER, 大家有兴趣的可以直接去mongodb的官网上查找, 不过查看了其mongo_find接口发现为同步调用, 这在服务器并发应用方面会受到限制, 通常服务器为了提高并发处理效率会使用异步接口. 开始的时候比较偷懒, 在其官网上留言想让其driver开发人员帮忙添加异步调用接口, 这事情也就先放下了... 2天过后, 等我想要接着制作的时候, 再次查看了官网动态... 发现死气沉沉的毫无反应... 我个人还算是比较勤快, 好在driver代码实在好读, 这点让我很佩服, 仔细的分析了下原尾, 决定自己为其添加一组异步调用接口 :)
ok, let's do it :)
由于鄙人资历经验尚浅... 如有不妥之处, 欢迎各位及时指正.
思路:
我们知道LUA中提供coroutine, 这极大的方便了我们开发异步调用, 首先, 我们需要明确异步查询流程: LUA脚本层发起查询请求, 调用引擎层接口发送查询请求, 返回LUA脚本层并挂起当前coroutine, --- (引擎处理其他事件) ---, 引擎收到mongodb返回查询结果, 组织封装结果并通知LUA脚本层唤醒查询请求coroutine, coroutine继续执行得到返回结果并处理.
由于有coroutine的帮助, 使得我们在LUA层面上的调用和正常的顺序编程没有区别, 而异步的回调处理过程完全被屏蔽在逻辑层之下, 大大的简化了我们的逻辑层编程复杂度, 而且提高了引擎并发处理能力.
实现:
好了, 接下来我们来看看如何实现这样的功能. 根据上面的思路, 我们需要首先解决一个问题, 如何正确的恢复一个被挂起的coroutine, 这里如果我们使用多个线程等待同一条连接上的请求响应时, 如果在未加锁保护的情况下会出现这样一种情况: 比如2个线程通过同一条连接请求A, B发送至数据库, 但接受情况为B, A. 因为加锁实属下策, 所以, 我们应当让数据库帮助我们记录一些信息以便在返回的结果中我们可以正确的唤醒相应的coroutine.
mongodb的消息头中包含了这样的字段, 我们可以暂且为其命名为query_id, 当我们在发送时填充该字段后, 在接受到的返回消息头中会原封不动的得到该query_id, 这样我们就可以简单的使用自增id作为query_id进行填充即可.
下面我们要用将原driv