修正datastore_cache无效的bug

标签:Google App Engine, Python

今天在尝试Alkis Evlogimenos的datastore_cache模块时,发现没有调用memcache,于是跟踪了半天代码,终于找到问题所在了。

这个bug解释起来非常麻烦,我也不清楚是不是Google更改了实现而导致的,先把API调用机制介绍一下吧。

在调用GAE的API时,app会根据服务名(例如'datastore_v3'、'memcache'等)来从一个stub_map(存根表)里获取API代理。接着将request和respone(都是PB对象)传给这个API代理,并根据不同的call名,发出相应的异步RPC。
可惜的是Google并不将异步API开放出来,到现在也只有异步urlfetch的开放API,所以要用的话,只能自己看代码了。这个异步RFC调用后,就执行了一个wait函数(于是变成了同步RFC),等待RFC返回,然后检查respone并返回。

而datastore_cache就是修改了这个存根表,将datastore_v3这个服务拦截了,加入了一层memcache。可虽然拦截了存根表,RPC的构造函数参数却忘记修改了,于是仍然是传原来的对象。

解决的办法很简单,自己写个CreateRPC即可。
先在模块头加上这行:
from google.appengine.api import apiproxy_rpc
然后在APIProxyShim类里加上这个方法:
  def CreateRPC(self):
    return apiproxy_rpc.RPC(stub=self)
于是问题解决。

顺带一提,作者写的文档貌似有问题。实际上DatastoreCachingShim实现了_Dynamic_Get,而没覆盖_Dynamic_RunQuery,所以对查询是无效的,和文档所说正好相反。
所以我也写了个实现:
  def _Dynamic_RunQuery(self, query, query_result):
    """Intercepts query results and caches the returned entities."""
    if query.has_transaction():
      self.CallWrappedStub('RunQuery', query, query_result)
      return

    key = 'RunQuery:' + query.Encode()
    results = memcache.get(key)
    if results is None:
      self.CallWrappedStub('RunQuery', query, query_result)
      memcache.set(key, query_result, 600)
    else:
      query_result.MergeFrom(results)

有需要的可以去这里下载修改后的源码

0条评论 你不来一发么↓

    想说点什么呢?